📄 inlineflowbox.cpp
字号:
{ int maxPositionTop = 0; int maxPositionBottom = 0; int maxAscent = 0; int maxDescent = 0; // Figure out if we're in strict mode. Note that we can't simply use !style()->htmlHacks(), // because that would match almost strict mode as well. RenderObject* curr = renderer(); while (curr && !curr->node()) curr = curr->container(); bool strictMode = (curr && curr->document()->inStrictMode()); computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom)) adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); int maxHeight = maxAscent + maxDescent; int topPosition = heightOfBlock; int bottomPosition = heightOfBlock; int selectionTop = heightOfBlock; int selectionBottom = heightOfBlock; placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); setVerticalOverflowPositions(topPosition, bottomPosition); setVerticalSelectionPositions(selectionTop, selectionBottom); heightOfBlock += maxHeight; return heightOfBlock;}void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom){ for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { // The computed lineheight needs to be extended for the // positioned elements if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. if (curr->y() == PositionTop || curr->y() == PositionBottom) { int lineHeight = curr->renderer()->lineHeight(m_firstLine); if (curr->y() == PositionTop) { if (maxAscent + maxDescent < lineHeight) maxDescent = lineHeight - maxAscent; } else { if (maxAscent + maxDescent < lineHeight) maxAscent = lineHeight - maxDescent; } if (maxAscent + maxDescent >= max(maxPositionTop, maxPositionBottom)) break; } if (curr->isInlineFlowBox()) static_cast<InlineFlowBox*>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); }}static int verticalPositionForBox(InlineBox* curr, bool firstLine){ if (curr->renderer()->isText()) return curr->parent()->y(); if (curr->renderer()->isBox()) return toRenderBox(curr->renderer())->verticalPosition(firstLine); return toRenderInline(curr->renderer())->verticalPositionFromCache(firstLine);}void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, int& maxAscent, int& maxDescent, bool strictMode){ if (isRootInlineBox()) { // Examine our root box. int lineHeight = renderer()->lineHeight(m_firstLine, true); int baseline = renderer()->baselinePosition(m_firstLine, true); if (hasTextChildren() || strictMode) { int ascent = baseline; int descent = lineHeight - ascent; if (maxAscent < ascent) maxAscent = ascent; if (maxDescent < descent) maxDescent = descent; } } for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. bool isInlineFlow = curr->isInlineFlowBox(); int lineHeight = curr->renderer()->lineHeight(m_firstLine); int baseline = curr->renderer()->baselinePosition(m_firstLine); curr->setY(verticalPositionForBox(curr, m_firstLine)); if (curr->y() == PositionTop) { if (maxPositionTop < lineHeight) maxPositionTop = lineHeight; } else if (curr->y() == PositionBottom) { if (maxPositionBottom < lineHeight) maxPositionBottom = lineHeight; } else if ((!isInlineFlow || static_cast<InlineFlowBox*>(curr)->hasTextChildren()) || curr->boxModelObject()->hasHorizontalBordersOrPadding() || strictMode) { int ascent = baseline - curr->y(); int descent = lineHeight - ascent; if (maxAscent < ascent) maxAscent = ascent; if (maxDescent < descent) maxDescent = descent; } if (curr->isInlineFlowBox()) static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); }}void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, bool strictMode, int& topPosition, int& bottomPosition, int& selectionTop, int& selectionBottom){ if (isRootInlineBox()) setY(yPos + max(0, maxAscent - renderer()->baselinePosition(m_firstLine, true))); // Place our root box. for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isPositioned()) continue; // Positioned placeholders don't affect calculations. // Adjust boxes to use their real box y/height and not the logical height (as dictated by // line-height). bool isInlineFlow = curr->isInlineFlowBox(); if (isInlineFlow) static_cast<InlineFlowBox*>(curr)->placeBoxesVertically(yPos, maxHeight, maxAscent, strictMode, topPosition, bottomPosition, selectionTop, selectionBottom); bool childAffectsTopBottomPos = true; if (curr->y() == PositionTop) curr->setY(yPos); else if (curr->y() == PositionBottom) curr->setY(yPos + maxHeight - curr->renderer()->lineHeight(m_firstLine)); else { if ((isInlineFlow && !static_cast<InlineFlowBox*>(curr)->hasTextChildren()) && !curr->boxModelObject()->hasHorizontalBordersOrPadding() && !strictMode) childAffectsTopBottomPos = false; int posAdjust = maxAscent - curr->renderer()->baselinePosition(m_firstLine); if (!childAffectsTopBottomPos) posAdjust = max(0, posAdjust); curr->setY(curr->y() + yPos + posAdjust); } int newY = curr->y(); int overflowTop = 0; int overflowBottom = 0; if (curr->isText() || curr->isInlineFlowBox()) { const Font& font = curr->renderer()->style(m_firstLine)->font(); newY += curr->renderer()->baselinePosition(m_firstLine) - font.ascent(); for (ShadowData* shadow = curr->renderer()->style()->textShadow(); shadow; shadow = shadow->next) { overflowTop = min(overflowTop, shadow->y - shadow->blur); overflowBottom = max(overflowBottom, shadow->y + shadow->blur); } for (ShadowData* boxShadow = curr->renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { overflowTop = min(overflowTop, boxShadow->y - boxShadow->blur); overflowBottom = max(overflowBottom, boxShadow->y + boxShadow->blur); } for (ShadowData* textShadow = curr->renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { overflowTop = min(overflowTop, textShadow->y - textShadow->blur); overflowBottom = max(overflowBottom, textShadow->y + textShadow->blur); } if (curr->renderer()->hasReflection()) { RenderBox* box = toRenderBox(curr->renderer()); overflowTop = min(overflowTop, box->reflectionBox().y()); overflowBottom = max(overflowBottom, box->reflectionBox().bottom()); } if (curr->isInlineFlowBox()) newY -= curr->boxModelObject()->borderTop() + curr->boxModelObject()->paddingTop(); } else if (!curr->renderer()->isBR()) { RenderBox* box = toRenderBox(curr->renderer()); newY += box->marginTop(); overflowTop = box->overflowTop(false); overflowBottom = box->overflowHeight(false) - box->height(); } curr->setY(newY); if (childAffectsTopBottomPos) { selectionTop = min(selectionTop, newY); selectionBottom = max(selectionBottom, newY + curr->height()); topPosition = min(topPosition, newY + overflowTop); bottomPosition = max(bottomPosition, newY + curr->height() + overflowBottom); } } if (isRootInlineBox()) { const Font& font = renderer()->style(m_firstLine)->font(); setY(y() + renderer()->baselinePosition(m_firstLine, true) - font.ascent()); if (hasTextChildren() || strictMode) { selectionTop = min(selectionTop, y()); selectionBottom = max(selectionBottom, y() + height()); } }}bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty){ // Check children first. for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, x, y, tx, ty)) { renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); return true; } } // Now check ourselves. IntRect rect(tx + m_x, ty + m_y, m_width, height()); if (visibleToHitTesting() && rect.contains(x, y)) { renderer()->updateHitTestResult(result, IntPoint(x - tx, y - ty)); // Don't add in m_x or m_y here, we want coords in the containing block's space. return true; } return false;}void InlineFlowBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty){ int xPos = tx + m_x - renderer()->maximalOutlineSize(paintInfo.phase); int w = width() + 2 * renderer()->maximalOutlineSize(paintInfo.phase); int shadowLeft = 0; int shadowRight = 0; for (ShadowData* boxShadow = renderer()->style(m_firstLine)->boxShadow(); boxShadow; boxShadow = boxShadow->next) { shadowLeft = min(boxShadow->x - boxShadow->blur, shadowLeft); shadowRight = max(boxShadow->x + boxShadow->blur, shadowRight); } for (ShadowData* textShadow = renderer()->style(m_firstLine)->textShadow(); textShadow; textShadow = textShadow->next) { shadowLeft = min(textShadow->x - textShadow->blur, shadowLeft); shadowRight = max(textShadow->x + textShadow->blur, shadowRight); } xPos += shadowLeft; w += -shadowLeft + shadowRight; bool intersectsDamageRect = xPos < paintInfo.rect.right() && xPos + w > paintInfo.rect.x(); if (intersectsDamageRect && paintInfo.phase != PaintPhaseChildOutlines) { if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) { // Add ourselves to the paint info struct's list of inlines that need to paint their // outlines. if (renderer()->style()->visibility() == VISIBLE && renderer()->hasOutline() && !isRootInlineBox()) { RenderInline* inlineFlow = toRenderInline(renderer()); if ((inlineFlow->continuation() || inlineFlow->isInlineContinuation()) && !boxModelObject()->hasSelfPaintingLayer()) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. RenderBlock* block = renderer()->containingBlock()->containingBlock(); block->addContinuationWithOutline(toRenderInline(renderer()->node()->renderer())); } else if (!inlineFlow->isInlineContinuation()) paintInfo.outlineObjects->add(inlineFlow); } } else if (paintInfo.phase == PaintPhaseMask) { paintMask(paintInfo, tx, ty); return; } else { // 1. Paint our background, border and box-shadow. paintBoxDecorations(paintInfo, tx, ty); // 2. Paint our underline and overline. paintTextDecorations(paintInfo, tx, ty, false); } } if (paintInfo.phase == PaintPhaseMask) return; PaintPhase paintPhase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase; RenderObject::PaintInfo childInfo(paintInfo); childInfo.phase = paintPhase; childInfo.paintingRoot = renderer()->paintingRootForChildren(paintInfo); // 3. Paint our children. if (paintPhase != PaintPhaseSelfOutline) { for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) curr->paint(childInfo, tx, ty); } } // 4. Paint our strike-through if (intersectsDamageRect && (paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection)) paintTextDecorations(paintInfo, tx, ty, true);}void InlineFlowBox::paintFillLayers(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int my, int mh, int _tx, int _ty, int w, int h, CompositeOperator op){ if (!fillLayer) return; paintFillLayers(paintInfo, c, fillLayer->next(), my, mh, _tx, _ty, w, h, op); paintFillLayer(paintInfo, c, fillLayer, my, mh, _tx, _ty, w, h, op);}void InlineFlowBox::paintFillLayer(const RenderObject::PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, int my, int mh, int tx, int ty, int w, int h, CompositeOperator op){ StyleImage* img = fillLayer->image(); bool hasFillImage = img && img->canRender(renderer()->style()->effectiveZoom()); if ((!hasFillImage && !renderer()->style()->hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, tx, ty, w, h, this, op); else { // We have a fill image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. // Think of background 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 background 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(); paintInfo.context->save(); paintInfo.context->clip(IntRect(tx, ty, width(), height())); boxModelObject()->paintFillLayerExtended(paintInfo, c, fillLayer, my, mh, startX, ty, totalWidth, h, this, op); paintInfo.context->restore(); }}void InlineFlowBox::paintBoxShadow(GraphicsContext* context, RenderStyle* s, int tx, int ty, int w, int h){ if ((!prevLineBox() && !nextLineBox()) || !parent()) boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s); else { // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines boxModelObject()->paintBoxShadow(context, tx, ty, w, h, s, includeLeftEdge(), includeRightEdge()); }}void InlineFlowBox::paintBoxDecorations(RenderObject::PaintInfo& paintInfo, int tx, int ty){ if (!renderer()->shouldPaintWithinRoot(paintInfo) || renderer()->style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; // Move x/y to our coordinates. tx += m_x;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -