Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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));
}
Exemplo n.º 3
0
IntRect RenderView::documentRect() const
{
    FloatRect overflowRect(unscaledDocumentRect());
    if (hasTransform())
        overflowRect = layer()->currentTransform().mapRect(overflowRect);
    return IntRect(overflowRect);
}
Exemplo n.º 4
0
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);
    }
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 8
0
int RenderView::docRight() const
{
    IntRect overflowRect(layoutOverflowRect());
    flipForWritingMode(overflowRect);
    if (hasTransform())
        overflowRect = layer()->currentTransform().mapRect(overflowRect);
    return overflowRect.maxX();
}
Exemplo n.º 9
0
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();
}
Exemplo n.º 11
0
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);
    }
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
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));
    }
}
Exemplo n.º 14
0
IntRect RenderView::unscaledDocumentRect() const
{
    LayoutRect overflowRect(layoutOverflowRect());
    flipForWritingMode(overflowRect);
    return pixelSnappedIntRect(overflowRect);
}
Exemplo n.º 15
0
IntRect RenderView::unscaledDocumentRect() const
{
    IntRect overflowRect(layoutOverflowRect());
    flipForWritingMode(overflowRect);
    return overflowRect;
}
Exemplo n.º 16
0
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);
        }
    }
}