void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, const SkPaint& skPaint) { fCpuMemorySize = sizeof(TextBlob); SkPaint runPaint(skPaint); for (SkTextBlobRunIterator iter(skBlob); !iter.done(); iter.next()) { iter.applyFontToPaint(&runPaint); // No need to re-seed the paint. if (runPaint.getTextSize() <= 0) { continue; } TextRun* run = this->addToTail(runPaint); const char* text = reinterpret_cast<const char*>(iter.glyphs()); size_t byteLength = sizeof(uint16_t) * iter.glyphCount(); const SkPoint& runOffset = iter.offset(); switch (iter.positioning()) { case SkTextBlob::kDefault_Positioning: run->setText(text, byteLength, runOffset.fX, runOffset.fY); break; case SkTextBlob::kHorizontal_Positioning: run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0, runOffset.fY)); break; case SkTextBlob::kFull_Positioning: run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0, 0)); break; } fCpuMemorySize += run->computeSizeInCache(); } }
void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) { if (paintingDisabled()) return; BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; bidiResolver.setStatus(BidiStatus(run.direction(), run.directionalOverride())); bidiResolver.setPosition(TextRunIterator(&run, 0)); // FIXME: This ownership should be reversed. We should pass BidiRunList // to BidiResolver in createBidiRunsForLine. BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs(); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); if (!bidiRuns.runCount()) return; FloatPoint currPoint = point; BidiCharacterRun* bidiRun = bidiRuns.firstRun(); while (bidiRun) { TextRun subrun = run; subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start()); bool isRTL = bidiRun->level() % 2; subrun.setDirection(isRTL ? RTL : LTR); subrun.setDirectionalOverride(bidiRun->dirOverride(false)); font.drawText(this, subrun, currPoint); bidiRun = bidiRun->next(); // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. if (bidiRun) currPoint.move(font.width(subrun), 0); } bidiRuns.deleteRuns(); }
void GraphicsContext::drawBidiText(const Font& font, const TextRun& run, const FloatPoint& point) { if (paintingDisabled()) return; BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver; WTF::Unicode::Direction paragraphDirection = run.ltr() ? WTF::Unicode::LeftToRight : WTF::Unicode::RightToLeft; bidiResolver.setStatus(BidiStatus(paragraphDirection, paragraphDirection, paragraphDirection, new BidiContext(run.ltr() ? 0 : 1, paragraphDirection, run.directionalOverride()))); bidiResolver.setPosition(TextRunIterator(&run, 0)); bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length())); if (!bidiResolver.runCount()) return; FloatPoint currPoint = point; BidiCharacterRun* bidiRun = bidiResolver.firstRun(); while (bidiRun) { TextRun subrun = run; subrun.setText(run.data(bidiRun->start()), bidiRun->stop() - bidiRun->start()); subrun.setRTL(bidiRun->level() % 2); subrun.setDirectionalOverride(bidiRun->dirOverride(false)); font.drawText(this, subrun, currPoint); bidiRun = bidiRun->next(); // FIXME: Have Font::drawText return the width of what it drew so that we don't have to re-measure here. if (bidiRun) currPoint.move(font.floatWidth(subrun), 0.f); } bidiResolver.deleteRuns(); }
void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, const SkPaint& skPaint, GrContext* ctx, const SkSurfaceProps* props) { fCpuMemorySize = sizeof(TextBlob); SkPaint runPaint(skPaint); for (SkTextBlob::RunIterator iter(skBlob); !iter.done(); iter.next()) { iter.applyFontToPaint(&runPaint); // No need to re-seed the paint. TextRun* run = SkNEW_INSERT_AT_LLIST_TAIL(this, TextRun, (runPaint)); const char* text = reinterpret_cast<const char*>(iter.glyphs()); size_t byteLength = sizeof(uint16_t) * iter.glyphCount(); const SkPoint& runOffset = iter.offset(); switch (iter.positioning()) { case SkTextBlob::kDefault_Positioning: run->setText(text, byteLength, runOffset.fX, runOffset.fY, ctx, props); break; case SkTextBlob::kHorizontal_Positioning: run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0, runOffset.fY), ctx, props); break; case SkTextBlob::kFull_Positioning: run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0, 0), ctx, props); break; } fCpuMemorySize += run->cpuMemorySize(); } }
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)); } }