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)); } }
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)); } }