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();
    }
}
예제 #2
0
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));
    }
}
예제 #6
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));
  }
}