📄 inlineflowbox.cpp
字号:
ty += m_y; int w = width(); int h = height(); int my = max(ty, paintInfo.rect.y()); int mh; if (ty < paintInfo.rect.y()) mh = max(0, h - (paintInfo.rect.y() - ty)); else mh = min(paintInfo.rect.height(), h); 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, tx, ty, w, h); Color c = styleToUse->backgroundColor(); paintFillLayers(paintInfo, c, styleToUse->backgroundLayers(), my, mh, 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, width(), height())); boxModelObject()->paintBorder(context, startX, ty, totalWidth, h, renderer()->style()); context->restore(); } } }}void InlineFlowBox::paintMask(RenderObject::PaintInfo& paintInfo, int tx, int ty){ if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; // Move x/y to our coordinates. tx += m_x; ty += m_y; int w = width(); int h = height(); int my = max(ty, paintInfo.rect.y()); int mh; if (ty < paintInfo.rect.y()) mh = max(0, h - (paintInfo.rect.y() - ty)); else mh = min(paintInfo.rect.height(), h); // Figure out if we need to push a transparency layer to render our mask. bool pushTransparencyLayer = false; const NinePieceImage& maskNinePieceImage = renderer()->style()->maskBoxImage(); StyleImage* maskBoxImage = renderer()->style()->maskBoxImage().image(); if ((maskBoxImage && renderer()->style()->maskLayers()->hasImage()) || renderer()->style()->maskLayers()->next()) pushTransparencyLayer = true; CompositeOperator compositeOp = CompositeDestinationIn; if (pushTransparencyLayer) { paintInfo.context->setCompositeOperation(CompositeDestinationIn); paintInfo.context->beginTransparencyLayer(1.0f); compositeOp = CompositeSourceOver; } paintFillLayers(paintInfo, Color(), renderer()->style()->maskLayers(), my, mh, tx, ty, w, h, compositeOp); bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(renderer()->style()->effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) return; // Don't paint anything while we wait for the image to load. // The simple case is where we are the only box for this object. In those // cases only a single call to draw is required. if (!prevLineBox() && !nextLineBox()) { boxModelObject()->paintNinePieceImage(paintInfo.context, tx, ty, w, h, renderer()->style(), maskNinePieceImage, compositeOp); } else { // We have a mask image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. 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(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); boxModelObject()->paintNinePieceImage(paintInfo.context, startX, ty, totalWidth, h, renderer()->style(), maskNinePieceImage, compositeOp); paintInfo.context->restore(); } if (pushTransparencyLayer) paintInfo.context->endTransparencyLayer();}static bool shouldDrawTextDecoration(RenderObject* obj){ for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) { if (curr->isRenderInline()) return true; if (curr->isText() && !curr->isBR()) { if (!curr->style()->collapseWhiteSpace()) return true; Node* currElement = curr->node(); if (!currElement) return true; if (!currElement->isTextNode()) return true; if (!static_cast<Text*>(currElement)->containsOnlyWhitespace()) return true; } } return false;}void InlineFlowBox::paintTextDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty, bool paintedChildren){ // Paint text decorations like underlines/overlines. We only do this if we aren't in quirks mode (i.e., in // almost-strict mode or strict mode). if (renderer()->style()->htmlHacks() || !renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE) return; // We don't want underlines or other decorations when we're trying to draw nothing but the selection as white text. if (paintInfo.phase == PaintPhaseSelection && paintInfo.forceBlackText) return; GraphicsContext* context = paintInfo.context; tx += m_x; ty += m_y; RenderStyle* styleToUse = renderer()->style(m_firstLine); int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect(); if (deco != TDNONE && ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) && shouldDrawTextDecoration(renderer())) { int x = m_x + borderLeft() + paddingLeft(); int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight()); RootInlineBox* rootLine = root(); if (rootLine->ellipsisBox()) { int ellipsisX = rootLine->ellipsisBox()->x(); int ellipsisWidth = rootLine->ellipsisBox()->width(); // FIXME: Will need to work with RTL if (rootLine == this) { if (x + w >= ellipsisX + ellipsisWidth) w -= (x + w - ellipsisX - ellipsisWidth); } else { if (x >= ellipsisX) return; if (x + w >= ellipsisX) w -= (x + w - ellipsisX); } } // We must have child boxes and have decorations defined. tx += borderLeft() + paddingLeft(); Color underline, overline, linethrough; underline = overline = linethrough = styleToUse->color(); if (!parent()) renderer()->getTextDecorationColors(deco, underline, overline, linethrough); bool isPrinting = renderer()->document()->printing(); context->setStrokeThickness(1.0f); // FIXME: We should improve this rule and not always just assume 1. bool paintUnderline = deco & UNDERLINE && !paintedChildren; bool paintOverline = deco & OVERLINE && !paintedChildren; bool paintLineThrough = deco & LINE_THROUGH && paintedChildren; bool linesAreOpaque = !isPrinting && (!paintUnderline || underline.alpha() == 255) && (!paintOverline || overline.alpha() == 255) && (!paintLineThrough || linethrough.alpha() == 255); int baselinePos = renderer()->style(m_firstLine)->font().ascent(); if (!isRootInlineBox()) baselinePos += borderTop() + paddingTop(); bool setClip = false; int extraOffset = 0; ShadowData* shadow = styleToUse->textShadow(); if (!linesAreOpaque && shadow && shadow->next) { IntRect clipRect(tx, ty, w, baselinePos + 2); for (ShadowData* s = shadow; s; s = s->next) { IntRect shadowRect(tx, ty, w, baselinePos + 2); shadowRect.inflate(s->blur); shadowRect.move(s->x, s->y); clipRect.unite(shadowRect); extraOffset = max(extraOffset, max(0, s->y) + s->blur); } context->save(); context->clip(clipRect); extraOffset += baselinePos + 2; ty += extraOffset; setClip = true; } bool setShadow = false; do { if (shadow) { if (!shadow->next) { // The last set of lines paints normally inside the clip. ty -= extraOffset; extraOffset = 0; } context->setShadow(IntSize(shadow->x, shadow->y - extraOffset), shadow->blur, shadow->color); setShadow = true; shadow = shadow->next; } if (paintUnderline) { context->setStrokeColor(underline); context->setStrokeStyle(SolidStroke); // Leave one pixel of white between the baseline and the underline. context->drawLineForText(IntPoint(tx, ty + baselinePos + 1), w, isPrinting); } if (paintOverline) { context->setStrokeColor(overline); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty), w, isPrinting); } if (paintLineThrough) { context->setStrokeColor(linethrough); context->setStrokeStyle(SolidStroke); context->drawLineForText(IntPoint(tx, ty + 2 * baselinePos / 3), w, isPrinting); } } while (shadow); if (setClip) context->restore(); else if (setShadow) context->clearShadow(); }}InlineBox* InlineFlowBox::firstLeafChild(){ return firstLeafChildAfterBox();}InlineBox* InlineFlowBox::lastLeafChild(){ return lastLeafChildBeforeBox();}InlineBox* InlineFlowBox::firstLeafChildAfterBox(InlineBox* start){ InlineBox* leaf = 0; for (InlineBox* box = start ? start->nextOnLine() : firstChild(); box && !leaf; box = box->nextOnLine()) leaf = box->firstLeafChild(); if (start && !leaf && parent()) return parent()->firstLeafChildAfterBox(this); return leaf;}InlineBox* InlineFlowBox::lastLeafChildBeforeBox(InlineBox* start){ InlineBox* leaf = 0; for (InlineBox* box = start ? start->prevOnLine() : lastChild(); box && !leaf; box = box->prevOnLine()) leaf = box->lastLeafChild(); if (start && !leaf && parent()) return parent()->lastLeafChildBeforeBox(this); return leaf;}RenderObject::SelectionState InlineFlowBox::selectionState(){ return RenderObject::SelectionNone;}bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth){ for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { if (!box->canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth)) return false; } return true;}int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox){ int result = -1; for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) { int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox); if (currResult != -1 && result == -1) result = currResult; } return result;}void InlineFlowBox::clearTruncation(){ for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) box->clearTruncation();}#ifndef NDEBUGvoid InlineFlowBox::checkConsistency() const{#ifdef CHECK_CONSISTENCY ASSERT(!m_hasBadChildList); const InlineBox* prev = 0; for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) { ASSERT(child->parent() == this); ASSERT(child->prevOnLine() == prev); prev = child; } ASSERT(prev == m_lastChild);#endif}#endif} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -