webkit进行最终绘制的逻辑是从frameview进行刷新调用
RenderLayer
RenderBlock
RenderBox
加入我们针对各个elemenet的定制的情况
下面我们看一个具体的调用的流程:
#0 WebCore::RenderTheme::paint (this=0x24eed0, o=0xd15fa8, paintInfo=@0x4ef83ee0, r=@0x4ef83e1c) at external/webkit/WebCore/rendering/RenderTheme.cpp:222
#1 0xa842f7c6 in WebCore::RenderBox::paintBoxDecorations (this=0xd15fa8, paintInfo=@0x4ef83ee0, tx=991, ty=103) at external/webkit/WebCore/rendering/RenderBox.cpp:636
#2 0xa8426eec in WebCore::RenderBlock::paintObject (this=0xd15fa8, paintInfo=@0x4ef83ee0, tx=1324891872, ty=103) at external/webkit/WebCore/rendering/RenderBlock.cpp:1729
#3 0xa84241fc in WebCore::RenderBlock::paint (this=0xd15fa8, paintInfo=@0x4ef83ee0, tx=991, ty=103) at external/webkit/WebCore/rendering/RenderBlock.cpp:1558
#4 0xa8416a78 in WebCore::InlineBox::paint (this=0xd8e158, paintInfo=@0x3df, tx=<value optimized out>, ty=101) at external/webkit/WebCore/rendering/InlineBox.cpp:173
#5 0xa8418b2a in WebCore::InlineFlowBox::paint (this=0xd8e17c, paintInfo=@0x4ef83fbc, tx=<value optimized out>, ty=<value optimized out>)
at external/webkit/WebCore/rendering/InlineFlowBox.cpp:673
#6 0xa8418b2a in WebCore::InlineFlowBox::paint (this=0xd8e1b8, paintInfo=@0x4ef84060, tx=<value optimized out>, ty=<value optimized out>)
at external/webkit/WebCore/rendering/InlineFlowBox.cpp:673
#7 0xa84712dc in WebCore::RootInlineBox::paint (this=0x24eed0, paintInfo=@0xd15fa8, tx=1324891872, ty=1324891676) at external/webkit/WebCore/rendering/RootInlineBox.cpp:166
#8 0xa844e0c0 in WebCore::RenderLineBoxList::paint (this=<value optimized out>, renderer=<value optimized out>, paintInfo=<value optimized out>, tx=<value optimized out>,
ty=101) at external/webkit/WebCore/rendering/RenderLineBoxList.cpp:204
#9 0xa8423e36 in WebCore::RenderBlock::paintContents (this=0xd15e38, paintInfo=@0x4ef84390, tx=991, ty=101) at external/webkit/WebCore/rendering/RenderBlock.cpp:1665
#10 0xa8426f6c in WebCore::RenderBlock::paintObject (this=0xd15e38, paintInfo=@0x4ef84390, tx=<value optimized out>, ty=101)
at external/webkit/WebCore/rendering/RenderBlock.cpp:1754
#11 0xa84241fc in WebCore::RenderBlock::paint (this=0xd15e38, paintInfo=@0x4ef84390, tx=991, ty=101) at external/webkit/WebCore/rendering/RenderBlock.cpp:1558
#12 0xa8449756 in WebCore::RenderLayer::paintLayer (this=0xd15eb0, rootLayer=<value optimized out>, p=0x4ef84a48, paintDirtyRect=<value optimized out>, paintBehavior=0,
paintingRoot=0x0, overlapTestRequests=0x4ef8495c, paintFlags=0) at external/webkit/WebCore/rendering/RenderLayer.cpp:2338
#13 0xa8449838 in WebCore::RenderLayer::paintLayer (this=0xacee9c, rootLayer=<value optimized out>, p=0x4ef84a48, paintDirtyRect=<value optimized out>, paintBehavior=0,
paintingRoot=0x0, overlapTestRequests=0x4ef8495c, paintFlags=0) at external/webkit/WebCore/rendering/RenderLayer.cpp:2363
#14 0xa8449838 in WebCore::RenderLayer::paintLayer (this=0xaced68, rootLayer=<value optimized out>, p=0x4ef84a48, paintDirtyRect=<value optimized out>, paintBehavior=0,
paintingRoot=0x0, overlapTestRequests=0x4ef8495c, paintFlags=0) at external/webkit/WebCore/rendering/RenderLayer.cpp:2363
#15 0xa8449976 in WebCore::RenderLayer::paint (this=<value optimized out>, p=0xa8449977, damageRect=@0x3df, paintBehavior=<value optimized out>, paintingRoot=0x0)
at external/webkit/WebCore/rendering/RenderLayer.cpp:2142
#16 0xa83d6f1c in WebCore::FrameView::paintContents (this=0xa7f0c0, p=<value optimized out>, rect=<value optimized out>) at external/webkit/WebCore/page/FrameView.cpp:1775
通过这个过程我们就可以看到最终调用到的RenderTheme的过程,实际上这些都是一些修饰的东西
修饰的东西的来源是paintBoxDecorations
而调用这个修饰之前的RenderBlock::paintObject就是对整个内容绘制
我们查看一下这个内容:
void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
{
PaintPhase paintPhase = paintInfo.phase;
// 1. paint background, borders etc
if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
if (hasBoxDecorations())
paintBoxDecorations(paintInfo, tx, ty);
if (hasColumns())
paintColumnRules(paintInfo, tx, ty);
}
if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
paintMask(paintInfo, tx, ty);
return;
}
// We're done. We don't bother painting any children.
if (paintPhase == PaintPhaseBlockBackground)
return;
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s
int scrolledX = tx;
int scrolledY = ty;
if (hasOverflowClip())
layer()->subtractScrolledContentOffset(scrolledX, scrolledY);
// 2. paint contents
if (paintPhase != PaintPhaseSelfOutline) {
if (hasColumns())
paintColumnContents(paintInfo, scrolledX, scrolledY);
else
paintContents(paintInfo, scrolledX, scrolledY);
}
// 3. paint selection
// FIXME: Make this work with multi column layouts. For now don't fill gaps.
bool isPrinting = document()->printing();
if (!isPrinting && !hasColumns())
paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
// 4. paint floats.
if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
if (hasColumns())
paintColumnContents(paintInfo, scrolledX, scrolledY, true);
else
paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
}
// 5. paint outline.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
paintOutline(paintInfo.context, tx, ty, width(), height(), style());
// 6. paint continuation outlines.
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) {
RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer());
if (!inlineRenderer->hasSelfPaintingLayer())
containingBlock()->addContinuationWithOutline(inlineRenderer);
else if (!inlineRenderer->firstLineBox())
inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(),
ty - y() + inlineRenderer->containingBlock()->y());
}
paintContinuationOutlines(paintInfo, tx, ty);
}
// 7. paint caret.
// If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
// then paint the caret.
if (paintPhase == PaintPhaseForeground) {
paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret);
paintCaret(paintInfo, scrolledX, scrolledY, DragCaret);
}
}
这个函数里面包含的paintContents就是对于内容的绘制过程
我们还发现这个paintBoxDecorations里面包含对于背景的绘制
void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty)
{
if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground)
return;
int x = m_x;
int y = m_y;
int w = width();
int h = height();
// Constrain our background/border painting to the line top and bottom if necessary.
bool strictMode = renderer()->document()->inStrictMode();
if (!hasTextChildren() && !strictMode) {
RootInlineBox* rootBox = root();
int bottom = min(rootBox->lineBottom(), y + h);
y = max(rootBox->lineTop(), y);
h = bottom - y;
}
// Move x/y to our coordinates.
tx += x;
ty += y;
GraphicsContext* context = paintInfo.context;
// You can use p::first-line to specify a background. If so, the root line boxes for
// a line may actually have to paint a background.
RenderStyle* styleToUse = renderer()->style(m_firstLine);
if ((!parent() && m_firstLine && styleToUse != renderer()->style()) || (parent() && renderer()->hasBoxDecorations())) {
// Shadow comes first and is behind the background and border.
if (styleToUse->boxShadow())
paintBoxShadow(context, styleToUse, Normal, tx, ty, w, h);
Color c = styleToUse->backgroundColor();
paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), tx, ty, w, h);
if (styleToUse->boxShadow())
paintBoxShadow(context, styleToUse, Inset, tx, ty, w, h);
// :first-line cannot be used to put borders on a line. Always paint borders with our
// non-first-line style.
if (parent() && renderer()->style()->hasBorder()) {
StyleImage* borderImage = renderer()->style()->borderImage().image();
bool hasBorderImage = borderImage && borderImage->canRender(styleToUse->effectiveZoom());
if (hasBorderImage && !borderImage->isLoaded())
return; // Don't paint anything while we wait for the image to load.
// The simple case is where we either have no border image or we are the only box for this object. In those
// cases only a single call to draw is required.
if (!hasBorderImage || (!prevLineBox() && !nextLineBox()))
boxModelObject()->paintBorder(context, tx, ty, w, h, renderer()->style(), includeLeftEdge(), includeRightEdge());
else {
// We have a border image that spans multiple lines.
// We need to adjust _tx and _ty by the width of all previous lines.
// Think of border image painting on inlines as though you had one long line, a single continuous
// strip. Even though that strip has been broken up across multiple lines, you still paint it
// as though you had one single line. This means each line has to pick up the image where
// the previous line left off.
// FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
// but it isn't even clear how this should work at all.
int xOffsetOnLine = 0;
for (InlineRunBox* curr = prevLineBox(); curr; curr = curr->prevLineBox())
xOffsetOnLine += curr->width();
int startX = tx - xOffsetOnLine;
int totalWidth = xOffsetOnLine;
for (InlineRunBox* curr = this; curr; curr = curr->nextLineBox())
totalWidth += curr->width();
context->save();
context->clip(IntRect(tx, ty, w, h));
boxModelObject()->paintBorder(context, startX, ty, totalWidth, h, renderer()->style());
context->restore();
}
}
}
}
paintFillLayers里面就是包含着对于背景的绘制
如果对这篇讲的技术有任何疑问,第一时间获得文章更新,每天发布一篇技术大牛的原创文章,更多技术信息分享。
欢迎关注个人微信公众平台:程序员互动联盟,扫一扫下方二维码或搜索微信号coder_online即可关注,在线帮您解决技术难点,给大牛直接出难题。
