void LayoutImage::computeIntrinsicSizingInfo( IntrinsicSizingInfo& intrinsicSizingInfo) const { LayoutReplaced::computeIntrinsicSizingInfo(intrinsicSizingInfo); // Our intrinsicSize is empty if we're laying out generated images with // relative width/height. Figure out the right intrinsic size to use. if (intrinsicSizingInfo.size.isEmpty() && m_imageResource->imageHasRelativeSize()) { LayoutObject* containingBlock = isOutOfFlowPositioned() ? container() : this->containingBlock(); if (containingBlock->isBox()) { LayoutBox* box = toLayoutBox(containingBlock); intrinsicSizingInfo.size.setWidth(box->availableLogicalWidth().toFloat()); intrinsicSizingInfo.size.setHeight( box->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); } } // Don't compute an intrinsic ratio to preserve historical WebKit behavior if // we're painting alt text and/or a broken image. // Video is excluded from this behavior because video elements have a default // aspect ratio that a failed poster image load should not override. if (m_imageResource && m_imageResource->errorOccurred() && !isVideo()) { intrinsicSizingInfo.aspectRatio = FloatSize(1, 1); return; } }
BackgroundBleedAvoidance BoxDecorationData::determineBackgroundBleedAvoidance(const LayoutBox& layoutBox) { if (layoutBox.isDocumentElement()) return BackgroundBleedNone; if (!hasBackground) return BackgroundBleedNone; const ComputedStyle& boxStyle = layoutBox.styleRef(); const bool hasBorderRadius = boxStyle.hasBorderRadius(); if (!hasBorderDecoration || !hasBorderRadius || layoutBox.canRenderBorderImage()) { if (layoutBox.backgroundShouldAlwaysBeClipped()) return BackgroundBleedClipOnly; // Border radius clipping may require layer bleed avoidance if we are going to draw // an image over something else, because we do not want the antialiasing to lead to bleeding if (boxStyle.hasBackgroundImage() && hasBorderRadius) { // But if the top layer is opaque for the purposes of background painting, we do not // need the bleed avoidance because we will not paint anything behind the top layer. // But only if we need to draw something underneath. const FillLayer& fillLayer = layoutBox.style()->backgroundLayers(); if ((backgroundColor.alpha() || fillLayer.next()) && !BoxPainter::isFillLayerOpaque(fillLayer, layoutBox)) return BackgroundBleedClipLayer; } return BackgroundBleedNone; } if (borderObscuresBackgroundEdge(boxStyle)) return BackgroundBleedShrinkBackground; return BackgroundBleedClipLayer; }
void LayoutMultiColumnFlowThread::skipColumnSpanner(LayoutBox* layoutObject, LayoutUnit logicalTopInFlowThread) { ASSERT(layoutObject->isColumnSpanAll()); LayoutMultiColumnSpannerPlaceholder* placeholder = layoutObject->spannerPlaceholder(); LayoutBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); if (previousColumnBox && previousColumnBox->isLayoutMultiColumnSet()) { LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(previousColumnBox); if (logicalTopInFlowThread < columnSet->logicalTopInFlowThread()) logicalTopInFlowThread = columnSet->logicalTopInFlowThread(); // Negative margins may cause this. columnSet->endFlow(logicalTopInFlowThread); } LayoutBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox(); if (nextColumnBox && nextColumnBox->isLayoutMultiColumnSet()) { LayoutMultiColumnSet* nextSet = toLayoutMultiColumnSet(nextColumnBox); m_lastSetWorkedOn = nextSet; nextSet->beginFlow(logicalTopInFlowThread); } // We'll lay out of spanners after flow thread layout has finished (during layout of the spanner // placeholders). There may be containing blocks for out-of-flow positioned descendants of the // spanner in the flow thread, so that out-of-flow objects inside the spanner will be laid out // as part of flow thread layout (even if the spanner itself won't). We need to add such // out-of-flow positioned objects to their containing blocks now, or they'll never get laid // out. Since it's non-trivial to determine if we need this, and where such out-of-flow objects // might be, just go through the whole subtree. for (LayoutObject* descendant = layoutObject->slowFirstChild(); descendant; descendant = descendant->nextInPreOrder()) { if (descendant->isBox() && descendant->isOutOfFlowPositioned()) descendant->containingBlock()->insertPositionedObject(toLayoutBox(descendant)); } }
void LayoutMultiColumnFlowThread::layoutColumns(SubtreeLayoutScope& layoutScope) { // Since we ended up here, it means that the multicol container (our parent) needed // layout. Since contents of the multicol container are diverted to the flow thread, the flow // thread needs layout as well. layoutScope.setChildNeedsLayout(this); m_blockOffsetInEnclosingFragmentationContext = enclosingFragmentationContext() ? multiColumnBlockFlow()->offsetFromLogicalTopOfFirstPage() : LayoutUnit(); for (LayoutBox* columnBox = firstMultiColumnBox(); columnBox; columnBox = columnBox->nextSiblingMultiColumnBox()) { if (!columnBox->isLayoutMultiColumnSet()) { ASSERT(columnBox->isLayoutMultiColumnSpannerPlaceholder()); // no other type is expected. continue; } LayoutMultiColumnSet* columnSet = toLayoutMultiColumnSet(columnBox); layoutScope.setChildNeedsLayout(columnSet); if (!m_columnHeightsChanged) { // This is the initial layout pass. We need to reset the column height, because contents // typically have changed. columnSet->resetColumnHeight(); } // Since column sets are regular block flow objects, and their position is changed in // regular block layout code (with no means for the multicol code to notice unless we add // hooks there), store the previous position now. If it changes in the imminent layout // pass, we may have to rebalance its columns. columnSet->storeOldPosition(); } m_columnHeightsChanged = false; invalidateColumnSets(); layout(); validateColumnSets(); }
void LayoutTableRow::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle) { ASSERT(style()->display() == TABLE_ROW); LayoutBox::styleDidChange(diff, oldStyle); propagateStyleToAnonymousChildren(); if (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight()) section()->rowLogicalHeightChanged(this); // If border was changed, notify table. if (parent()) { LayoutTable* table = this->table(); if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border()) table->invalidateCollapsedBorders(); if (table && oldStyle && diff.needsFullLayout() && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, style())) { // If the border width changes on a row, we need to make sure the cells in the row know to lay out again. // This only happens when borders are collapsed, since they end up affecting the border sides of the cell // itself. for (LayoutBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { if (!childBox->isTableCell()) continue; childBox->setChildNeedsLayout(); } } } }
void LayoutTextControlSingleLine::autoscroll(const IntPoint& position) { LayoutBox* layoutObject = innerEditorElement()->layoutBox(); if (!layoutObject) return; layoutObject->autoscroll(position); }
void CanvasRenderingContext2D::scrollPathIntoViewInternal(const Path& path) { if (!state().isTransformInvertible() || path.isEmpty()) return; canvas()->document().updateStyleAndLayoutIgnorePendingStylesheets(); LayoutObject* renderer = canvas()->layoutObject(); LayoutBox* layoutBox = canvas()->layoutBox(); if (!renderer || !layoutBox) return; // Apply transformation and get the bounding rect Path transformedPath = path; transformedPath.transform(state().transform()); FloatRect boundingRect = transformedPath.boundingRect(); // Offset by the canvas rect LayoutRect pathRect(boundingRect); IntRect canvasRect = layoutBox->absoluteContentBox(); pathRect.moveBy(canvasRect.location()); renderer->scrollRectToVisible(pathRect, ScrollAlignment::alignCenterAlways, ScrollAlignment::alignTopAlways); // TODO: should implement "inform the user" that the caret and/or // selection the specified rectangle of the canvas. See // http://crbug.com/357987 }
TEST_F(ScrollingCoordinatorTest, fastFractionalScrollingDiv) { registerMockedHttpURLLoad("fractional-scroll-div.html"); navigateTo(m_baseURL + "fractional-scroll-div.html"); forceFullCompositingUpdate(); Document* document = frame()->document(); Element* scrollableElement = document->getElementById("scroller"); ASSERT(scrollableElement); scrollableElement->setScrollTop(1.0); scrollableElement->setScrollLeft(1.0); forceFullCompositingUpdate(); // Make sure the fractional scroll offset change 1.0 -> 1.2 gets propagated // to compositor. scrollableElement->setScrollTop(1.2); scrollableElement->setScrollLeft(1.2); forceFullCompositingUpdate(); LayoutObject* layoutObject = scrollableElement->layoutObject(); ASSERT_TRUE(layoutObject->isBox()); LayoutBox* box = toLayoutBox(layoutObject); ASSERT_TRUE(box->usesCompositedScrolling()); CompositedLayerMapping* compositedLayerMapping = box->layer()->compositedLayerMapping(); ASSERT_TRUE(compositedLayerMapping->hasScrollingLayer()); ASSERT(compositedLayerMapping->scrollingContentsLayer()); WebLayer* webScrollLayer = compositedLayerMapping->scrollingContentsLayer()->platformLayer(); ASSERT_TRUE(webScrollLayer); ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().x, 0.01); ASSERT_NEAR(1.2, webScrollLayer->scrollPositionDouble().y, 0.01); }
void FieldsetPainter::paintMask(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (m_layoutFieldset.style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; LayoutRect paintRect = LayoutRect(paintOffset, m_layoutFieldset.size()); LayoutBox* legend = m_layoutFieldset.findInFlowLegend(); if (!legend) return BoxPainter(m_layoutFieldset).paintMask(paintInfo, paintOffset); if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutFieldset, paintInfo.phase, paintOffset)) return; // FIXME: We need to work with "rl" and "bt" block flow directions. In those // cases the legend is embedded in the right and bottom borders respectively. // https://bugs.webkit.org/show_bug.cgi?id=47236 if (m_layoutFieldset.style()->isHorizontalWritingMode()) { LayoutUnit yOff = (legend->location().y() > LayoutUnit()) ? LayoutUnit() : (legend->size().height() - m_layoutFieldset.borderTop()) / 2; paintRect.expand(LayoutUnit(), -yOff); paintRect.move(LayoutUnit(), yOff); } else { LayoutUnit xOff = (legend->location().x() > LayoutUnit()) ? LayoutUnit() : (legend->size().width() - m_layoutFieldset.borderLeft()) / 2; paintRect.expand(-xOff, LayoutUnit()); paintRect.move(xOff, LayoutUnit()); } LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutFieldset, paintInfo.phase, paintRect, paintOffset); BoxPainter(m_layoutFieldset).paintMaskImages(paintInfo, paintRect); }
LayoutBox* LayoutBox::create() { LayoutBox* ret = new LayoutBox(); if (ret->init()) return ret; else return NULL; }
HTMLAreaElement* HitTestResult::imageAreaForImage() const { ASSERT(m_innerNode); HTMLImageElement* imageElement = nullptr; if (isHTMLImageElement(m_innerNode)) { imageElement = toHTMLImageElement(m_innerNode); } else if (m_innerNode->isInShadowTree()) { if (m_innerNode->containingShadowRoot()->type() == ShadowRootType::UserAgent) { if (isHTMLImageElement(m_innerNode->shadowHost())) imageElement = toHTMLImageElement(m_innerNode->shadowHost()); } } if (!imageElement || !imageElement->layoutObject() || !imageElement->layoutObject()->isBox()) return nullptr; HTMLMapElement* map = imageElement->treeScope().getImageMap(imageElement->fastGetAttribute(usemapAttr)); if (!map) return nullptr; LayoutBox* box = toLayoutBox(imageElement->layoutObject()); LayoutRect contentBox = box->contentBoxRect(); float scaleFactor = 1 / box->style()->effectiveZoom(); LayoutPoint location = localPoint(); location.scale(scaleFactor, scaleFactor); return map->areaForPoint(location, contentBox.size()); }
static FloatPoint perspectiveOrigin(const LayoutBox& box) { const ComputedStyle& style = box.styleRef(); FloatSize borderBoxSize(box.size()); return FloatPoint( floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); }
bool Init() override { m_commonGUIStyle = g_commonGUIStyle; m_canvas = Utility::MakeRef(new Canvas()); // Load textures for song select m_style = SongSelectStyle::Get(g_application); // Split between statistics and selection wheel (in percentage) const float screenSplit = 0.4f; // Statistics window m_statisticsWindow = Ref<SongStatistics>(new SongStatistics(m_style)); Canvas::Slot* statisticsSlot = m_canvas->Add(m_statisticsWindow.As<GUIElementBase>()); statisticsSlot->anchor = Anchor(0, 0, screenSplit, 1.0f); statisticsSlot->SetZOrder(2); // Background Panel* background = new Panel(); background->imageFillMode = FillMode::Fill; background->texture = g_application->LoadTexture("bg.png"); background->color = Color(0.5f); Canvas::Slot* bgSlot = m_canvas->Add(background->MakeShared()); bgSlot->anchor = Anchors::Full; bgSlot->SetZOrder(-2); LayoutBox* box = new LayoutBox(); Canvas::Slot* boxSlot = m_canvas->Add(box->MakeShared()); boxSlot->anchor = Anchor(screenSplit, 0, 1.0f, 1.0f); box->layoutDirection = LayoutBox::Vertical; { m_searchField = Ref<TextInputField>(new TextInputField(m_commonGUIStyle)); LayoutBox::Slot* searchFieldSlot = box->Add(m_searchField.As<GUIElementBase>()); searchFieldSlot->fillX = true; m_searchField->OnTextUpdated.Add(this, &SongSelect_Impl::OnSearchTermChanged); m_selectionWheel = Ref<SelectionWheel>(new SelectionWheel(m_style)); LayoutBox::Slot* selectionSlot = box->Add(m_selectionWheel.As<GUIElementBase>()); selectionSlot->fillY = true; m_selectionWheel->OnMapSelected.Add(this, &SongSelect_Impl::OnMapSelected); m_selectionWheel->OnDifficultySelected.Add(this, &SongSelect_Impl::OnDifficultySelected); } // Select interface sound m_selectSound = g_audio->CreateSample("audio/menu_click.wav"); // Setup the map database m_mapDatabase.AddSearchPath(g_gameConfig.GetString(GameConfigKeys::SongFolder)); m_mapDatabase.OnMapsAdded.Add(m_selectionWheel.GetData(), &SelectionWheel::OnMapsAdded); m_mapDatabase.OnMapsUpdated.Add(m_selectionWheel.GetData(), &SelectionWheel::OnMapsUpdated); m_mapDatabase.OnMapsRemoved.Add(m_selectionWheel.GetData(), &SelectionWheel::OnMapsRemoved); m_mapDatabase.OnMapsCleared.Add(m_selectionWheel.GetData(), &SelectionWheel::OnMapsCleared); m_mapDatabase.StartSearching(); m_selectionWheel->SelectRandom(); return true; }
static LayoutRect getShapeImageMarginRect(const LayoutBox& layoutBox, const LayoutSize& referenceBoxLogicalSize) { LayoutPoint marginBoxOrigin(-layoutBox.marginLogicalLeft() - layoutBox.borderAndPaddingLogicalLeft(), -layoutBox.marginBefore() - layoutBox.borderBefore() - layoutBox.paddingBefore()); LayoutSize marginBoxSizeDelta(layoutBox.marginLogicalWidth() + layoutBox.borderAndPaddingLogicalWidth(), layoutBox.marginLogicalHeight() + layoutBox.borderAndPaddingLogicalHeight()); LayoutSize marginRectSize(referenceBoxLogicalSize + marginBoxSizeDelta); marginRectSize.clampNegativeToZero(); return LayoutRect(marginBoxOrigin, marginRectSize); }
static FloatPoint3D transformOrigin(const LayoutBox& box) { const ComputedStyle& style = box.styleRef(); FloatSize borderBoxSize(box.size()); return FloatPoint3D( floatValueForLength(style.transformOriginX(), borderBoxSize.width()), floatValueForLength(style.transformOriginY(), borderBoxSize.height()), style.transformOriginZ()); }
BoxDecorationData::BoxDecorationData(const LayoutBox& layoutBox) { backgroundColor = layoutBox.style()->visitedDependentColor(CSSPropertyBackgroundColor); hasBackground = backgroundColor.alpha() || layoutBox.style()->hasBackgroundImage(); ASSERT(hasBackground == layoutBox.style()->hasBackground()); hasBorderDecoration = layoutBox.style()->hasBorderDecoration(); hasAppearance = layoutBox.style()->hasAppearance(); bleedAvoidance = determineBackgroundBleedAvoidance(layoutBox); }
void BlockPainter::paintChild(const LayoutBox& child, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint childPoint = m_layoutBlock.flipForWritingModeForChild(&child, paintOffset); if (!child.hasSelfPaintingLayer() && !child.isFloating() && !child.isColumnSpanAll()) child.paint(paintInfo, childPoint); }
LayoutState::LayoutState(LayoutBox& layoutObject, bool containingBlockLogicalWidthChanged) : m_containingBlockLogicalWidthChanged(containingBlockLogicalWidthChanged), m_next(layoutObject.view()->layoutState()), m_layoutObject(layoutObject) { if (layoutObject.isLayoutFlowThread()) m_flowThread = toLayoutFlowThread(&layoutObject); else m_flowThread = m_next->flowThread(); m_paginationStateChanged = m_next->m_paginationStateChanged; layoutObject.view()->pushLayoutState(*this); m_heightOffsetForTableHeaders = m_next->heightOffsetForTableHeaders(); if (layoutObject.isLayoutFlowThread()) { // Entering a new pagination context. m_paginationOffset = LayoutSize(); m_isPaginated = true; return; } // Disable pagination for objects we don't support. For now this includes // overflow:scroll/auto, inline blocks and writing mode roots. Additionally, // pagination inside SVG is not allowed. if (layoutObject.getPaginationBreakability() == LayoutBox::ForbidBreaks || (m_layoutObject.isSVG() && !m_layoutObject.isSVGRoot())) { m_flowThread = nullptr; m_isPaginated = false; return; } m_isPaginated = m_next->m_isPaginated; if (!m_isPaginated) return; // Now adjust the pagination offset, so that we can easily figure out how far // away we are from the start of the pagination context. m_paginationOffset = m_next->m_paginationOffset; bool fixed = layoutObject.isOutOfFlowPositioned() && layoutObject.style()->position() == FixedPosition; if (fixed) return; m_paginationOffset = m_next->m_paginationOffset + layoutObject.locationOffset(); if (!layoutObject.isOutOfFlowPositioned()) return; if (LayoutObject* container = layoutObject.container()) { if (container->style()->hasInFlowPosition() && container->isLayoutInline()) { m_paginationOffset += toLayoutInline(container)->offsetForInFlowPositionedInline( layoutObject); } } // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if // present. }
void BlockPainter::paintAllChildPhasesAtomically( const LayoutBox& child, const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutPoint childPoint = m_layoutBlock.flipForWritingModeForChild(&child, paintOffset); if (!child.hasSelfPaintingLayer() && !child.isFloating()) ObjectPainter(child).paintAllPhasesAtomically(paintInfo, childPoint); }
void LayoutSlider::layout() { // FIXME: Find a way to cascade appearance. // http://webkit.org/b/62535 LayoutBox* thumbBox = sliderThumbElement()->layoutBox(); if (thumbBox && thumbBox->isSliderThumb()) toLayoutSliderThumb(thumbBox)->updateAppearance(styleRef()); LayoutFlexibleBox::layout(); }
static LayoutObject* lastLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { LayoutBox* sibling = multicolSet->nextSiblingMultiColumnBox(); if (!sibling) return nullptr; // By right we should return lastLeafChild() here, but the caller doesn't care, so just return 0. // Adjacent column content sets should not occur. We would have no way of figuring out what each // of them contains then. ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread(); return previousInPreOrderSkippingOutOfFlow(multicolSet->multiColumnFlowThread(), spanner); }
static LayoutObject* firstLayoutObjectInSet(LayoutMultiColumnSet* multicolSet) { LayoutBox* sibling = multicolSet->previousSiblingMultiColumnBox(); if (!sibling) return multicolSet->flowThread()->firstChild(); // Adjacent column content sets should not occur. We would have no way of figuring out what each // of them contains then. ASSERT(sibling->isLayoutMultiColumnSpannerPlaceholder()); LayoutBox* spanner = toLayoutMultiColumnSpannerPlaceholder(sibling)->layoutObjectInFlowThread(); return nextInPreOrderAfterChildrenSkippingOutOfFlow(multicolSet->multiColumnFlowThread(), spanner); }
void LayoutMultiColumnSpannerPlaceholder::willBeRemovedFromTree() { if (m_layoutObjectInFlowThread) { LayoutBox* exSpanner = m_layoutObjectInFlowThread; m_layoutObjectInFlowThread->clearSpannerPlaceholder(); // Even if the placeholder is going away, the object in the flow thread might live on. Since // it's not a spanner anymore, it needs to be relaid out. exSpanner->setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReason::ColumnsChanged); } LayoutBox::willBeRemovedFromTree(); }
inline LayoutUnit borderBeforeInWritingMode(const LayoutBox& layoutBox, WritingMode writingMode) { switch (writingMode) { case TopToBottomWritingMode: return layoutBox.borderTop(); case LeftToRightWritingMode: return layoutBox.borderLeft(); case RightToLeftWritingMode: return layoutBox.borderRight(); } ASSERT_NOT_REACHED(); return layoutBox.borderBefore(); }
void ColumnBalancer::traverseSubtree(const LayoutBox& box) { if (box.childrenInline() && box.isLayoutBlockFlow()) { // Look for breaks between lines. traverseLines(toLayoutBlockFlow(box)); } // Look for breaks between and inside block-level children. Even if this is a // block flow with inline children, there may be interesting floats to examine // here. traverseChildren(box); }
void ColumnBalancer::traverseSubtree(const LayoutBox& box) { if (box.childrenInline() && box.isLayoutBlockFlow()) { // Look for breaks between lines. for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox(); line; line = line->nextRootBox()) { LayoutUnit lineTopInFlowThread = m_flowThreadOffset + line->lineTopWithLeading(); if (lineTopInFlowThread < group().logicalTopInFlowThread()) continue; if (lineTopInFlowThread >= group().logicalBottomInFlowThread()) break; examineLine(*line); } } const LayoutFlowThread* flowThread = group().columnSet().flowThread(); bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode(); // Look for breaks between and inside block-level children. Even if this is a block flow with // inline children, there may be interesting floats to examine here. for (const LayoutObject* child = box.slowFirstChild(); child; child = child->nextSibling()) { if (!child->isBox() || child->isInline()) continue; const LayoutBox& childBox = toLayoutBox(*child); LayoutRect overflowRect = childBox.layoutOverflowRect(); LayoutUnit childLogicalBottomWithOverflow = childBox.logicalTop() + (isHorizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX()); if (m_flowThreadOffset + childLogicalBottomWithOverflow <= group().logicalTopInFlowThread()) { // This child is fully above the fragmentainer group we're examining. continue; } LayoutUnit childLogicalTopWithOverflow = childBox.logicalTop() + (isHorizontalWritingMode ? overflowRect.y() : overflowRect.x()); if (m_flowThreadOffset + childLogicalTopWithOverflow >= group().logicalBottomInFlowThread()) { // This child is fully below the fragmentainer group we're examining. We cannot just // stop here, though, thanks to negative margins. So keep looking. continue; } if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll()) continue; // Tables are wicked. Both table rows and table cells are relative to their table section. LayoutUnit offsetForThisChild = childBox.isTableRow() ? LayoutUnit() : childBox.logicalTop(); m_flowThreadOffset += offsetForThisChild; examineBoxAfterEntering(childBox); // Unless the child is unsplittable, or if the child establishes an inner multicol // container, we descend into its subtree for further examination. if (childBox.paginationBreakability() != LayoutBox::ForbidBreaks && (!childBox.isLayoutBlockFlow() || !toLayoutBlockFlow(childBox).multiColumnFlowThread())) traverseSubtree(childBox); examineBoxBeforeLeaving(childBox); m_flowThreadOffset -= offsetForThisChild; } }
void MinimumSpaceShortageFinder::examineBoxBeforeLeaving(const LayoutBox& box) { if (m_pendingStrut == LayoutUnit::min() || box.paginationBreakability() != LayoutBox::ForbidBreaks) return; // The previous break was before a breakable block. Here's the first piece of unbreakable // content after / inside that block. We want to record the distance from the top of the column // to the bottom of this box as space shortage. LayoutUnit logicalOffsetFromCurrentColumn = flowThreadOffset() - group().columnLogicalTopForOffset(flowThreadOffset()); recordSpaceShortage(logicalOffsetFromCurrentColumn + box.logicalHeight() - m_pendingStrut); m_pendingStrut = LayoutUnit::min(); }
void LayoutMultiColumnFlowThread::destroySpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder* placeholder) { if (LayoutBox* nextColumnBox = placeholder->nextSiblingMultiColumnBox()) { LayoutBox* previousColumnBox = placeholder->previousSiblingMultiColumnBox(); if (nextColumnBox && nextColumnBox->isLayoutMultiColumnSet() && previousColumnBox && previousColumnBox->isLayoutMultiColumnSet()) { // Need to merge two column sets. nextColumnBox->destroy(); invalidateColumnSets(); } } placeholder->destroy(); }
inline LayoutUnit borderStartWithStyleForWritingMode(const LayoutBox& layoutBox, const ComputedStyle* style) { if (style->isHorizontalWritingMode()) { if (style->isLeftToRightDirection()) return layoutBox.borderLeft(); return layoutBox.borderRight(); } if (style->isLeftToRightDirection()) return layoutBox.borderTop(); return layoutBox.borderBottom(); }
// Returns true if the scroll control is invalidated. static bool invalidatePaintOfScrollControlIfNeeded(const LayoutRect& newPaintInvalidationRect, const LayoutRect& previousPaintInvalidationRect, bool needsPaintInvalidation, LayoutBox& box, const LayoutBoxModelObject& paintInvalidationContainer) { bool shouldInvalidateNewRect = needsPaintInvalidation; if (newPaintInvalidationRect != previousPaintInvalidationRect) { box.invalidatePaintUsingContainer(paintInvalidationContainer, previousPaintInvalidationRect, PaintInvalidationScroll); shouldInvalidateNewRect = true; } if (shouldInvalidateNewRect) { box.invalidatePaintUsingContainer(paintInvalidationContainer, newPaintInvalidationRect, PaintInvalidationScroll); box.enclosingLayer()->setNeedsRepaint(); return true; } return false; }