前话:
webkit是一个复杂的程序,复杂意味着简单,也是最基本的东西,下面是我对webkit在android中不支持scrollbar而写的文章,是说为什么不支持,以及怎么解决,我已经完全解决了这个问题。并在android 2.0中实现。 文章当初是用英文写的,因为也想让国外的朋友能读到,但没有国外的blog,也就先发在这里了。
文章并没有写全,因为最近事情比较多,我会慢慢写完。
原谅我的语法错误,拼写错误!
How to support scroll bar in webkit of android platform
Jian Jun
In platform such as qt , webkit support scrollbar , as well as google’s chrom ,which use webkit as it’s web enghine . but google’s another system ,android, haven’t support scroll bar . it just let the overflow area big enough to show all the things in the scroll bar . in this text , I will show you how to add some code to webkit to let android do support scroll bar. here we go.
1 How scroll bar come from
Scroll bar comes from css tags “overflow”. Bellow it is a html text.
it’s DIV ‘css attribute is define at style mydiv , it show that , the div area in the html page , which is a square area ,with width of 100px , height of 100px,it’s border is line of style solid red . after it overflow attribute , it’s define as “scroll” , which mean , if the div tag have some child html tags ,and child tags is too big to let div to hold it in it’s area which is 100*100 at the example ,the div will show a scroll bar , so user can use it to view all of it child . the overflow have some other attribute , we don’t show dettel it at here , cause just it’s “scroll” value will generate a scroll bar .
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HEAD>
<TITLE>Anonymous text interrupted by a block</TITLE>
<STYLE type="text/css">
.mydiv {
width: 100px;
height: 100px;
border: solid red;
border-width: 3px;
overflow:scroll
}
</STYLE>
</HEAD>
<BODY >
<div class=" mydiv ">
<a>china is a great country , every people like it very much</a>
</div>
</BODY>
</HTML>
2 How webit draw the scroll bar in other platform
Before we start , we should know how the webkit draw scroll bar in web page ,then we can do with android . though android haven’t draw it ,but in others platform ,such as qt , it support ,so, let’s we first insight how qt draw the scroll bar .
2.1 when to draw the scroll bar .
In the RenderBlock Class , there is a method called paint() . bellow is last line of this method . when the program goes there , it start to draw scrolls . but in android , it never goes there ( hasOverflowClip() always return false ) .i will tell how to let it return true when necessary .
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
// sit above the background/border.
if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo))
layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect);
the layer() above refer to RenderLayer .let view it .
void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
{
// Don't do anything if we have no overflow.
if (!renderer()->hasOverflowClip())
return;
// Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
// widgets can move without layout occurring (most notably when you scroll a document that
// contains fixed positioned elements).
positionOverflowControls(tx, ty);
// Now that we're sure the scrollbars are in the right place, paint them.
if (m_hBar)
m_hBar->paint(context, damageRect);
if (m_vBar)
m_vBar->paint(context, damageRect);
// We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
// edge of the box.
paintScrollCorner(context, tx, ty, damageRect);
// Paint our resizer last, since it sits on top of the scroll corner.
paintResizer(context, tx, ty, damageRect);
}
In the paintOverflowControls method , there is a call to positionOverflowControls(tx, ty) , this method is very important bellow is it’s content .
void RenderLayer::positionOverflowControls(int tx, int ty)
{
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
return;
RenderBox* box = renderBox();
if (!box)
return;
IntRect borderBox = box->borderBoxRect();
IntRect scrollCorner(scrollCornerRect(this, borderBox));
IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height()); // 把 borderBox 转换 成屏幕上的 绝对 坐 标
if (m_vBar) // 设 置垂直 滚动 条的矩形
m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(),
absBounds.y() + box->borderTop(),
m_vBar->width(),
absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
if (m_hBar) // 设 置水平 滚动 条的矩形
m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(),
absBounds.bottom() - box->borderBottom() - m_hBar->height(),
absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
m_hBar->height()));
if (m_scrollCorner)
m_scrollCorner->setFrameRect(scrollCorner);
if (m_resizer)
m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
}
m_vBar refers to vertical scroll bar , m_hBar refers to horizontal scroll bar . m_scrollCorner refers to the square corner between vertical scroll bar and horizontal scroll bar ,it’s at bottown right often . what this function do is to compute and set the three widget’s position in the web page . after the coordinate is set , the paintOverflowControls method will call m_vBar and the m_hBar ‘s paint method to draw the draw bar .now ,let say what’s the inside of Scrollbar’s (the Class of m_vBar and the m_hBar) paint method .
Scrollbar is a class defined at WebCore/platform directory . so it’s platform depended. Now let’s view it’s paint() function .
void Scrollbar::paint(GraphicsContext* context, const IntRect& damageRect)
{
if (context->updatingControlTints() && theme()->supportsControlTints()) {
invalidate();
return;
}
if (context->paintingDisabled() || !frameRect().intersects(damageRect))
return;
if (!theme()->paint(this, context, damageRect))
Widget::paint(context, damageRect);
}
Oh! This function is clear . it call one of another two paint method instead,paint of ScrollbarTheme class and paint of Widget Class . as we read the code , we know if ScrollbarTheme’s paint method return false , it will call Widget’s paint method .
Let’s view ScrollbarTheme’s paint method , we are more closer to the reality ! ScrollbarTheme is a platform depended Class as well , in qt , it’s realized in ScrollbarThemeQt Sub Class . bellow is it’s paint method .
bool ScrollbarThemeQt::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect)
{
if (graphicsContext->updatingControlTints()) {
scrollbar->invalidateRect(damageRect);
return false;
}
StylePainter p(this, graphicsContext);
if (!p.isValid())
return true;
p.painter->save();
QStyleOptionSlider* opt = styleOptionSlider(scrollbar, p.widget);
p.painter->setClipRect(opt->rect.intersected(damageRect), Qt::IntersectClip);
#ifdef Q_WS_MAC
p.drawComplexControl(QStyle::CC_ScrollBar, *opt);
#else
const QPoint topLeft = opt->rect.topLeft();
p.painter->translate(topLeft);
opt->rect.moveTo(QPoint(0, 0));
// The QStyle expects the background to be already filled
p.painter->fillRect(opt->rect, opt->palette.background());
p.drawComplexControl(QStyle::CC_ScrollBar, *opt);
opt->rect.moveTo(topLeft);
#endif
p.painter->restore();
return true;
}
We needn’t to read this code detailed . it just call the Qt’s graphic method to draw the scroll bar . finally it return true .as it return true,in ScrollBar’s paint method ,it didn’t call Widget’s paint method anymore .
3 How android avoid to draw the scroll bar
I mentioned that in platform of android ,it’s just let the overflow area bit enough to ensure all the content in the overflow area displayed . it’s done at ScrollView . another Class in the WebCore/platform directory .
1 let scrollbar off:
In WebCore/platform/ScrollViewAndroid.cpp file , there is a method named platformScrollbarModes , it set both of vertical and horizontal scroll bar mode to ScrollbarAlwaysOff .
2 Don’t generate a render layer for overflow
In platform such as qt , the webkit generate a render layer (a RenderLayer Class) for the overflow . but android didn’t do se it .