static FloatRect toNormalizedRect(const FloatRect& absoluteRect, const LayoutObject* layoutObject, const LayoutBlock* container) { ASSERT(layoutObject); ASSERT(container || layoutObject->isLayoutView()); if (!container) return FloatRect(); // We want to normalize by the max layout overflow size instead of only the visible bounding box. // Quads and their enclosing bounding boxes need to be used in order to keep results transform-friendly. FloatPoint scrolledOrigin; // For overflow:scroll we need to get where the actual origin is independently of the scroll. if (container->hasOverflowClip()) scrolledOrigin = -IntPoint(container->scrolledContentOffset()); FloatRect overflowRect(scrolledOrigin, FloatSize(container->maxLayoutOverflow())); FloatRect containerRect = container->localToAbsoluteQuad(FloatQuad(overflowRect)).enclosingBoundingBox(); if (containerRect.isEmpty()) return FloatRect(); // Make the coordinates relative to the container enclosing bounding box. // Since we work with rects enclosing quad unions this is still transform-friendly. FloatRect normalizedRect = absoluteRect; normalizedRect.moveBy(-containerRect.location()); // Fixed positions do not make sense in this coordinate system, but need to leave consistent tickmarks. // So, use their position when the view is not scrolled, like an absolute position. if (layoutObject->style()->position() == FixedPosition && container->isLayoutView()) normalizedRect.moveBy(-toLayoutView(container)->frameView()->scrollPosition()); normalizedRect.scale(1 / containerRect.width(), 1 / containerRect.height()); return normalizedRect; }
void DetailsMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground || m_layoutDetailsMarker.style()->visibility() != VISIBLE) { BlockPainter(m_layoutDetailsMarker).paint(paintInfo, paintOffset); return; } if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_layoutDetailsMarker, paintInfo.phase, paintOffset)) return; LayoutPoint boxOrigin(paintOffset + m_layoutDetailsMarker.location()); LayoutRect overflowRect(m_layoutDetailsMarker.visualOverflowRect()); overflowRect.moveBy(boxOrigin); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; LayoutObjectDrawingRecorder layoutDrawingRecorder(paintInfo.context, m_layoutDetailsMarker, paintInfo.phase, overflowRect, paintOffset); const Color color(m_layoutDetailsMarker.resolveColor(CSSPropertyColor)); paintInfo.context.setStrokeColor(color); paintInfo.context.setStrokeStyle(SolidStroke); paintInfo.context.setStrokeThickness(1.0f); paintInfo.context.setFillColor(color); boxOrigin.move(m_layoutDetailsMarker.borderLeft() + m_layoutDetailsMarker.paddingLeft(), m_layoutDetailsMarker.borderTop() + m_layoutDetailsMarker.paddingTop()); paintInfo.context.fillPath(getPath(boxOrigin)); }
IntRect RenderView::documentRect() const { FloatRect overflowRect(unscaledDocumentRect()); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); return IntRect(overflowRect); }
void InlineFlowBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutUnit lineTop, const LayoutUnit lineBottom) { ASSERT(!shouldPaintSelfOutline(paintInfo.phase) && !shouldPaintDescendantOutlines(paintInfo.phase)); LayoutRect overflowRect(m_inlineFlowBox.visualOverflowRect(lineTop, lineBottom)); m_inlineFlowBox.flipForWritingMode(overflowRect); overflowRect.moveBy(paintOffset); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; if (paintInfo.phase == PaintPhaseMask) { if (DrawingRecorder::useCachedDrawingIfPossible(paintInfo.context, m_inlineFlowBox, DisplayItem::paintPhaseToDrawingType(paintInfo.phase))) return; DrawingRecorder recorder(paintInfo.context, m_inlineFlowBox, DisplayItem::paintPhaseToDrawingType(paintInfo.phase), pixelSnappedIntRect(overflowRect)); paintMask(paintInfo, paintOffset); return; } if (paintInfo.phase == PaintPhaseForeground) { // Paint our background, border and box-shadow. paintBoxDecorationBackground(paintInfo, paintOffset, overflowRect); } // Paint our children. PaintInfo childInfo(paintInfo); for (InlineBox* curr = m_inlineFlowBox.firstChild(); curr; curr = curr->nextOnLine()) { if (curr->lineLayoutItem().isText() || !curr->boxModelObject().hasSelfPaintingLayer()) curr->paint(childInfo, paintOffset, lineTop, lineBottom); } }
bool RenderSVGContainer::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) { if (!viewport().isEmpty() && style()->overflowX() == OHIDDEN && style()->overflowY() == OHIDDEN) { int tx = _tx + m_x; int ty = _ty + m_y; // Check if we need to do anything at all. IntRect overflowBox = overflowRect(false); overflowBox.move(tx, ty); AffineTransform ctm = RenderContainer::absoluteTransform(); ctm.translate(viewport().x(), viewport().y()); double localX, localY; ctm.inverse().map(_x + _tx, _y + _ty, &localX, &localY); if (!overflowBox.contains((int)localX, (int)localY)) return false; } for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtPoint(request, result, _x, _y, _tx, _ty, hitTestAction)) { updateHitTestResult(result, IntPoint(_x - _tx, _y - _ty)); return true; } } // Spec: Only graphical elements can be targeted by the mouse, period. // 16.4: "If there are no graphics elements whose relevant graphics content is under the pointer (i.e., there is no target element), the event is not dispatched." return false; }
NS_IMETHODIMP nsTextBoxFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState) { if (mNeedsReflowCallback) { nsIReflowCallback* cb = new nsAsyncAccesskeyUpdate(this); if (cb) { PresContext()->PresShell()->PostReflowCallback(cb); } mNeedsReflowCallback = PR_FALSE; } mState |= NS_STATE_NEED_LAYOUT; nsresult rv = nsLeafBoxFrame::DoLayout(aBoxLayoutState); const nsStyleText* textStyle = GetStyleText(); if (textStyle->mTextShadow) { nsPoint origin(0,0); nsRect textRect = CalcTextRect(*aBoxLayoutState.GetRenderingContext(), origin); nsRect overflowRect(nsLayoutUtils::GetTextShadowRectsUnion(textRect, this)); overflowRect.UnionRect(overflowRect, nsRect(nsPoint(0, 0), GetSize())); FinishAndStoreOverflow(&overflowRect, GetSize()); } return rv; }
IntRect RenderReplaced::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) { if (style()->visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) return IntRect(); // The selectionRect can project outside of the overflowRect, so take their union // for repainting to avoid selection painting glitches. IntRect r = unionRect(localSelectionRect(false), overflowRect(false)); RenderView* v = view(); if (v) { // FIXME: layoutDelta needs to be applied in parts before/after transforms and // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 r.move(v->layoutDelta()); } if (style()) { if (style()->hasAppearance()) // The theme may wish to inflate the rect used when repainting. theme()->adjustRepaintRect(this, r); if (v) r.inflate(style()->outlineSize()); } computeRectForRepaint(repaintContainer, r); return r; }
int RenderView::docRight() const { IntRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); return overflowRect.maxX(); }
int RenderView::docTop() const { IntRect overflowRect(0, minYLayoutOverflow(), 0, maxYLayoutOverflow() - minYLayoutOverflow()); flipForWritingMode(overflowRect); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); return overflowRect.y(); }
void RenderLayerScrollableArea::updateAfterOverflowRecalc() { computeScrollDimensions(); if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { int clientWidth = box().pixelSnappedClientWidth(); horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); } if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { int clientHeight = box().pixelSnappedClientHeight(); verticalScrollbar->setProportion(clientHeight, overflowRect().height()); } bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) box().setNeedsLayoutAndFullPaintInvalidation(); }
void TablePainter::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { PaintPhase paintPhase = paintInfo.phase; if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && m_layoutTable.hasBoxDecorationBackground() && m_layoutTable.style()->visibility() == VISIBLE) paintBoxDecorationBackground(paintInfo, paintOffset); if (paintPhase == PaintPhaseMask) { paintMask(paintInfo, paintOffset); return; } // We're done. We don't bother painting any children. if (paintPhase == PaintPhaseBlockBackground) return; // We don't paint our own background, but we do let the kids paint their backgrounds. if (paintPhase == PaintPhaseChildBlockBackgrounds) paintPhase = PaintPhaseChildBlockBackground; PaintInfo info(paintInfo); info.phase = paintPhase; info.updatePaintingRootForChildren(&m_layoutTable); for (LayoutObject* child = m_layoutTable.firstChild(); child; child = child->nextSibling()) { if (child->isBox() && !toLayoutBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) { LayoutPoint childPoint = m_layoutTable.flipForWritingModeForChild(toLayoutBox(child), paintOffset); child->paint(info, childPoint); } } if (m_layoutTable.collapseBorders() && paintPhase == PaintPhaseChildBlockBackground && m_layoutTable.style()->visibility() == VISIBLE) { // Using our cached sorted styles, we then do individual passes, // painting each style of border from lowest precedence to highest precedence. info.phase = PaintPhaseCollapsedTableBorders; LayoutTable::CollapsedBorderValues collapsedBorders = m_layoutTable.collapsedBorders(); size_t count = collapsedBorders.size(); for (size_t i = 0; i < count; ++i) { // FIXME: pass this value into children rather than storing temporarily on the LayoutTable object. m_layoutTable.setCurrentBorderValue(&collapsedBorders[i]); for (LayoutTableSection* section = m_layoutTable.bottomSection(); section; section = m_layoutTable.sectionAbove(section)) { LayoutPoint childPoint = m_layoutTable.flipForWritingModeForChild(section, paintOffset); section->paint(info, childPoint); } } m_layoutTable.setCurrentBorderValue(0); } // Paint outline. if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && m_layoutTable.style()->hasOutline() && m_layoutTable.style()->visibility() == VISIBLE) { LayoutRect overflowRect(m_layoutTable.visualOverflowRect()); overflowRect.moveBy(paintOffset); ObjectPainter(m_layoutTable).paintOutline(paintInfo, LayoutRect(paintOffset, m_layoutTable.size()), overflowRect); } }
LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, LayoutUnit colGap) const { // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column // gap along interior edges. // // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of // the last column. This applies only to the true first column and last column across all column sets. // // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting // mode that understands not to paint contents from a previous column in the overflow area of a following column. // This problem applies to regions and pages as well and is not unique to columns. bool isFirstColumn = !index; bool isLastColumn = index == colCount - 1; bool isLeftmostColumn = style()->isLeftToRightDirection() ? isFirstColumn : isLastColumn; bool isRightmostColumn = style()->isLeftToRightDirection() ? isLastColumn : isFirstColumn; LayoutRect overflowRect(portionRect); if (isHorizontalWritingMode()) { if (isLeftmostColumn) { // Shift to the logical left overflow of the flow thread to make sure it's all covered. overflowRect.shiftXEdgeTo(min(flowThread()->visualOverflowRect().x(), portionRect.x())); } else { // Expand into half of the logical left column gap. overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2); } if (isRightmostColumn) { // Shift to the logical right overflow of the flow thread to ensure content can spill out of the column. overflowRect.shiftMaxXEdgeTo(max(flowThread()->visualOverflowRect().maxX(), portionRect.maxX())); } else { // Expand into half of the logical right column gap. overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap / 2); } } else { if (isLeftmostColumn) { // Shift to the logical left overflow of the flow thread to make sure it's all covered. overflowRect.shiftYEdgeTo(min(flowThread()->visualOverflowRect().y(), portionRect.y())); } else { // Expand into half of the logical left column gap. overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2); } if (isRightmostColumn) { // Shift to the logical right overflow of the flow thread to ensure content can spill out of the column. overflowRect.shiftMaxYEdgeTo(max(flowThread()->visualOverflowRect().maxY(), portionRect.maxY())); } else { // Expand into half of the logical right column gap. overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap / 2); } } return overflowRectForFlowThreadPortion(overflowRect, isFirstRegion() && isFirstColumn, isLastRegion() && isLastColumn); }
void ListMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutListMarker.style()->visibility() != VISIBLE) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(*paintInfo.context, m_layoutListMarker, paintInfo.phase, paintOffset)) return; LayoutPoint boxOrigin(paintOffset + m_layoutListMarker.location()); LayoutRect overflowRect(m_layoutListMarker.visualOverflowRect()); if (m_layoutListMarker.selectionState() != SelectionNone) overflowRect.unite(m_layoutListMarker.localSelectionRect()); overflowRect.moveBy(boxOrigin); IntRect pixelSnappedOverflowRect = pixelSnappedIntRect(overflowRect); if (!paintInfo.rect.intersects(pixelSnappedOverflowRect)) return; LayoutObjectDrawingRecorder recorder(*paintInfo.context, m_layoutListMarker, paintInfo.phase, pixelSnappedOverflowRect, paintOffset); LayoutRect box(boxOrigin, m_layoutListMarker.size()); IntRect marker = m_layoutListMarker.getRelativeMarkerRect(); marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext* context = paintInfo.context; if (m_layoutListMarker.isImage()) { context->drawImage(m_layoutListMarker.image()->image(&m_layoutListMarker, marker.size()).get(), marker); if (m_layoutListMarker.selectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context->fillRect(pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } return; } if (m_layoutListMarker.selectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context->fillRect(pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } const Color color(m_layoutListMarker.resolveColor(CSSPropertyColor)); context->setStrokeColor(color); context->setStrokeStyle(SolidStroke); context->setStrokeThickness(1.0f); context->setFillColor(color); EListStyleType type = m_layoutListMarker.style()->listStyleType(); switch (type) { case Disc: context->fillEllipse(marker); return; case Circle: context->strokeEllipse(marker); return; case Square: context->fillRect(marker); return; case NoneListStyle: return; case ArabicIndic: case Armenian: case Bengali: case Cambodian: case CJKIdeographic: case CjkEarthlyBranch: case CjkHeavenlyStem: case DecimalLeadingZero: case DecimalListStyle: case Devanagari: case EthiopicHalehame: case EthiopicHalehameAm: case EthiopicHalehameTiEr: case EthiopicHalehameTiEt: case Georgian: case Gujarati: case Gurmukhi: case Hebrew: case Hangul: case HangulConsonant: case KoreanHangulFormal: case KoreanHanjaFormal: case KoreanHanjaInformal: case Hiragana: case HiraganaIroha: case Kannada: case Katakana: case KatakanaIroha: case Khmer: case Lao: case LowerAlpha: case LowerArmenian: case LowerGreek: case LowerLatin: case LowerRoman: case Malayalam: case Mongolian: case Myanmar: case Oriya: case Persian: case SimpChineseFormal: case SimpChineseInformal: case Telugu: case Thai: case Tibetan: case TradChineseFormal: case TradChineseInformal: case UpperAlpha: case UpperArmenian: case UpperLatin: case UpperRoman: case Urdu: break; } if (m_layoutListMarker.text().isEmpty()) return; const Font& font = m_layoutListMarker.style()->font(); TextRun textRun = constructTextRun(font, m_layoutListMarker.text(), m_layoutListMarker.styleRef()); GraphicsContextStateSaver stateSaver(*context, false); if (!m_layoutListMarker.style()->isHorizontalWritingMode()) { marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); marker.moveBy(IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_layoutListMarker.logicalHeight()))); stateSaver.save(); context->translate(marker.x(), marker.maxY()); context->rotate(static_cast<float>(deg2rad(90.))); context->translate(-marker.x(), -marker.maxY()); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = marker; IntPoint textOrigin = IntPoint(marker.x(), marker.y() + m_layoutListMarker.style()->fontMetrics().ascent()); // Text is not arbitrary. We can judge whether it's RTL from the first character, // and we only need to handle the direction RightToLeft for now. bool textNeedsReversing = WTF::Unicode::direction(m_layoutListMarker.text()[0]) == WTF::Unicode::RightToLeft; StringBuilder reversedText; if (textNeedsReversing) { unsigned length = m_layoutListMarker.text().length(); reversedText.reserveCapacity(length); for (int i = length - 1; i >= 0; --i) reversedText.append(m_layoutListMarker.text()[i]); ASSERT(reversedText.length() == length); textRun.setText(reversedText.toString()); } const UChar suffix = m_layoutListMarker.listMarkerSuffix(type, m_layoutListMarker.listItem()->value()); UChar suffixStr[2] = { m_layoutListMarker.style()->isLeftToRightDirection() ? suffix : static_cast<UChar>(' '), m_layoutListMarker.style()->isLeftToRightDirection() ? static_cast<UChar>(' ') : suffix }; TextRun suffixRun = constructTextRun(font, suffixStr, 2, m_layoutListMarker.styleRef(), m_layoutListMarker.style()->direction()); TextRunPaintInfo suffixRunInfo(suffixRun); suffixRunInfo.bounds = marker; if (m_layoutListMarker.style()->isLeftToRightDirection()) { context->drawText(font, textRunPaintInfo, textOrigin); context->drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { context->drawText(font, suffixRunInfo, textOrigin); context->drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } }
IntRect RenderView::unscaledDocumentRect() const { LayoutRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); return pixelSnappedIntRect(overflowRect); }
IntRect RenderView::unscaledDocumentRect() const { IntRect overflowRect(layoutOverflowRect()); flipForWritingMode(overflowRect); return overflowRect; }
void ListMarkerPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; if (m_layoutListMarker.style()->visibility() != EVisibility::Visible) return; if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( paintInfo.context, m_layoutListMarker, paintInfo.phase)) return; LayoutPoint boxOrigin(paintOffset + m_layoutListMarker.location()); LayoutRect overflowRect(m_layoutListMarker.visualOverflowRect()); overflowRect.moveBy(boxOrigin); IntRect pixelSnappedOverflowRect = pixelSnappedIntRect(overflowRect); if (!paintInfo.cullRect().intersectsCullRect(overflowRect)) return; LayoutObjectDrawingRecorder recorder(paintInfo.context, m_layoutListMarker, paintInfo.phase, pixelSnappedOverflowRect); LayoutRect box(boxOrigin, m_layoutListMarker.size()); IntRect marker = m_layoutListMarker.getRelativeMarkerRect(); marker.moveBy(roundedIntPoint(boxOrigin)); GraphicsContext& context = paintInfo.context; if (m_layoutListMarker.isImage()) { context.drawImage(m_layoutListMarker.image() ->image(m_layoutListMarker, marker.size(), m_layoutListMarker.styleRef().effectiveZoom()) .get(), marker); if (m_layoutListMarker.getSelectionState() != SelectionNone) { LayoutRect selRect = m_layoutListMarker.localSelectionRect(); selRect.moveBy(boxOrigin); context.fillRect( pixelSnappedIntRect(selRect), m_layoutListMarker.listItem()->selectionBackgroundColor()); } return; } LayoutListMarker::ListStyleCategory styleCategory = m_layoutListMarker.getListStyleCategory(); if (styleCategory == LayoutListMarker::ListStyleCategory::None) return; Color color(m_layoutListMarker.resolveColor(CSSPropertyColor)); if (BoxPainter::shouldForceWhiteBackgroundForPrintEconomy( m_layoutListMarker.styleRef(), m_layoutListMarker.listItem()->document())) color = TextPainter::textColorForWhiteBackground(color); // Apply the color to the list marker text. context.setFillColor(color); const EListStyleType listStyle = m_layoutListMarker.style()->listStyleType(); if (styleCategory == LayoutListMarker::ListStyleCategory::Symbol) { paintSymbol(context, color, marker, listStyle); return; } if (m_layoutListMarker.text().isEmpty()) return; const Font& font = m_layoutListMarker.style()->font(); TextRun textRun = constructTextRun(font, m_layoutListMarker.text(), m_layoutListMarker.styleRef()); GraphicsContextStateSaver stateSaver(context, false); if (!m_layoutListMarker.style()->isHorizontalWritingMode()) { marker.moveBy(roundedIntPoint(-boxOrigin)); marker = marker.transposedRect(); marker.moveBy( IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_layoutListMarker.logicalHeight()))); stateSaver.save(); context.translate(marker.x(), marker.maxY()); context.rotate(static_cast<float>(deg2rad(90.))); context.translate(-marker.x(), -marker.maxY()); } TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = marker; const SimpleFontData* fontData = m_layoutListMarker.style()->font().primaryFont(); IntPoint textOrigin = IntPoint( marker.x(), marker.y() + (fontData ? fontData->getFontMetrics().ascent() : 0)); // Text is not arbitrary. We can judge whether it's RTL from the first // character, and we only need to handle the direction RightToLeft for now. bool textNeedsReversing = WTF::Unicode::direction(m_layoutListMarker.text()[0]) == WTF::Unicode::RightToLeft; StringBuilder reversedText; if (textNeedsReversing) { unsigned length = m_layoutListMarker.text().length(); reversedText.reserveCapacity(length); for (int i = length - 1; i >= 0; --i) reversedText.append(m_layoutListMarker.text()[i]); DCHECK(reversedText.length() == length); textRun.setText(reversedText.toString()); } const UChar suffix = ListMarkerText::suffix(listStyle, m_layoutListMarker.listItem()->value()); UChar suffixStr[2] = {suffix, static_cast<UChar>(' ')}; TextRun suffixRun = constructTextRun(font, suffixStr, 2, m_layoutListMarker.styleRef(), m_layoutListMarker.style()->direction()); TextRunPaintInfo suffixRunInfo(suffixRun); suffixRunInfo.bounds = marker; if (m_layoutListMarker.style()->isLeftToRightDirection()) { context.drawText(font, textRunPaintInfo, textOrigin); context.drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0)); } else { context.drawText(font, suffixRunInfo, textOrigin); context.drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0)); } }
void RenderLayerScrollableArea::updateAfterLayout() { m_scrollDimensionsDirty = true; IntSize originalScrollOffset = adjustedScrollOffset(); computeScrollDimensions(); // Layout may cause us to be at an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); if (clampedScrollOffset != adjustedScrollOffset()) scrollToOffset(clampedScrollOffset); if (originalScrollOffset != adjustedScrollOffset()) scrollToOffsetWithoutAnimation(-scrollOrigin() + adjustedScrollOffset()); bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // overflow:scroll should just enable/disable. if (box().style()->overflowX() == OSCROLL) horizontalScrollbar()->setEnabled(hasHorizontalOverflow); if (box().style()->overflowY() == OSCROLL) verticalScrollbar()->setEnabled(hasVerticalOverflow); } // overflow:auto may need to lay out again if scrollbars got added/removed. bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { if (box().hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(hasHorizontalOverflow); if (box().hasAutoVerticalScrollbar()) setHasVerticalScrollbar(hasVerticalOverflow); layer()->updateSelfPaintingLayer(); if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; SubtreeLayoutScope layoutScope(box()); layoutScope.setNeedsLayout(&box()); if (box().isRenderBlock()) { RenderBlock& block = toRenderBlock(box()); block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); block.layoutBlock(true); } else { box().layout(); } m_inOverflowRelayout = false; } } } { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // Set up the range (and page step/line step). if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { int clientWidth = box().pixelSnappedClientWidth(); horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); } if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { int clientHeight = box().pixelSnappedClientHeight(); verticalScrollbar->setProportion(clientHeight, overflowRect().height()); } } bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow(); updateScrollableAreaSet(hasOverflow); if (hasOverflow) { DisableCompositingQueryAsserts disabler; positionOverflowControls(IntSize()); } }
void InlineFlowBoxPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutUnit lineTop, const LayoutUnit lineBottom) { LayoutRect overflowRect(m_inlineFlowBox.visualOverflowRect(lineTop, lineBottom)); m_inlineFlowBox.flipForWritingMode(overflowRect); overflowRect.moveBy(paintOffset); if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) return; 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 (m_inlineFlowBox.layoutObject().style()->visibility() == VISIBLE && m_inlineFlowBox.layoutObject().style()->hasOutline() && !m_inlineFlowBox.isRootInlineBox()) { LayoutInline& inlineFlow = toLayoutInline(m_inlineFlowBox.layoutObject()); LayoutBlock* cb = 0; bool containingBlockPaintsContinuationOutline = inlineFlow.continuation() || inlineFlow.isInlineElementContinuation(); if (containingBlockPaintsContinuationOutline) { // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations // after a child removal. As a result, those merged inlines do not get seperated and hence not get enclosed by // anonymous blocks. In this case, it is better to bail out and paint it ourself. LayoutBlock* enclosingAnonymousBlock = m_inlineFlowBox.layoutObject().containingBlock(); if (!enclosingAnonymousBlock->isAnonymousBlock()) { containingBlockPaintsContinuationOutline = false; } else { cb = enclosingAnonymousBlock->containingBlock(); for (LayoutBoxModelObject* box = m_inlineFlowBox.boxModelObject(); box != cb; box = box->parent()->enclosingBoxModelObject()) { if (box->hasSelfPaintingLayer()) { containingBlockPaintsContinuationOutline = false; break; } } } } if (containingBlockPaintsContinuationOutline) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. cb->addContinuationWithOutline(toLayoutInline(m_inlineFlowBox.layoutObject().node()->layoutObject())); } else if (!inlineFlow.isInlineElementContinuation()) { paintInfo.outlineObjects()->add(&inlineFlow); } } } else if (paintInfo.phase == PaintPhaseMask) { DrawingRecorder recorder(*paintInfo.context, m_inlineFlowBox, DisplayItem::paintPhaseToDrawingType(paintInfo.phase), pixelSnappedIntRect(overflowRect)); if (!recorder.canUseCachedDrawing()) paintMask(paintInfo, paintOffset); return; } else if (paintInfo.phase == PaintPhaseForeground) { // Paint our background, border and box-shadow. paintBoxDecorationBackground(paintInfo, paintOffset); } // Paint our children. if (paintInfo.phase != PaintPhaseSelfOutline) { PaintInfo childInfo(paintInfo); childInfo.phase = paintInfo.phase == PaintPhaseChildOutlines ? PaintPhaseOutline : paintInfo.phase; if (childInfo.paintingRoot && childInfo.paintingRoot->isDescendantOf(&m_inlineFlowBox.layoutObject())) childInfo.paintingRoot = 0; else childInfo.updatePaintingRootForChildren(&m_inlineFlowBox.layoutObject()); for (InlineBox* curr = m_inlineFlowBox.firstChild(); curr; curr = curr->nextOnLine()) { if (curr->layoutObject().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) curr->paint(childInfo, paintOffset, lineTop, lineBottom); } } }