예제 #1
0
파일: Font.cpp 프로젝트: Chingliu/EAWebkit
void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
    // This glyph buffer holds our glyphs+advances+font data for each glyph.
    GlyphBuffer glyphBuffer;

    float startX = point.x();
    WidthIterator it(this, run);
    it.advance(from);
    float beforeWidth = it.m_runWidthSoFar;
    it.advance(to, &glyphBuffer);
    
    // We couldn't generate any glyphs for the run.  Give up.
    if (glyphBuffer.isEmpty())
        return;
    
    float afterWidth = it.m_runWidthSoFar;

    if (run.rtl()) {
        float finalRoundingWidth = it.m_finalRoundingWidth;
        it.advance(run.length());
        startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
    } else
        startX += beforeWidth;

    // Swap the order of the glyphs if right-to-left.
    if (run.rtl())
        for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
            glyphBuffer.swap(i, end);

    // Calculate the starting point of the glyphs to be displayed by adding
    // all the advances up to the first glyph.
    FloatPoint startPoint(startX, point.y());
    drawGlyphBuffer(context, glyphBuffer, run, startPoint);
}
예제 #2
0
float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
{
    float initialAdvance;

    WidthIterator it(this, run, 0, false, forTextEmphasis);
    // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
    // ligatures are enabled.
    GlyphBuffer localGlyphBuffer;
    it.advance(from, &localGlyphBuffer);
    float beforeWidth = it.m_runWidthSoFar;
    it.advance(to, &glyphBuffer);

    if (glyphBuffer.isEmpty())
        return 0;

    float afterWidth = it.m_runWidthSoFar;

    if (run.rtl()) {
        float finalRoundingWidth = it.m_finalRoundingWidth;
        it.advance(run.length(), &localGlyphBuffer);
        initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
    } else {
        initialAdvance = beforeWidth;
    }

    if (run.rtl())
        glyphBuffer.reverse(0, glyphBuffer.size());

    return initialAdvance;
}
예제 #3
0
    TextRunWalker(const TextRun& run, unsigned startingX, const Font* font)
        : m_font(font)
        , m_run(run)
        , m_startingX(startingX)
        , m_offsetX(m_startingX)
        , m_iterateBackwards(run.rtl())
    {
        memset(&m_item, 0, sizeof(m_item));
        // We cannot know, ahead of time, how many glyphs a given script run
        // will produce. We take a guess that script runs will not produce more
        // than twice as many glyphs as there are code points and fallback if
        // we find that we are wrong.
        m_maxGlyphs = run.length() * 2;
        createGlyphArrays();

        m_item.log_clusters = new unsigned short[run.length()];

        m_item.face = 0;
        m_item.font = allocHarfbuzzFont();

        m_item.string = run.characters();
        m_item.stringLength = run.length();
        m_item.item.bidiLevel = run.rtl();

        reset();
    }
예제 #4
0
float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
{
    float initialAdvance;

    WidthIterator it(this, run, 0, false, forTextEmphasis);
    it.advance(from);
    float beforeWidth = it.m_runWidthSoFar;
    it.advance(to, &glyphBuffer);

    if (glyphBuffer.isEmpty())
        return 0;

    float afterWidth = it.m_runWidthSoFar;

    if (run.rtl()) {
        it.advance(run.length());
        initialAdvance = it.m_runWidthSoFar - afterWidth;
    } else
        initialAdvance = beforeWidth;

    if (run.rtl()) {
        for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
            glyphBuffer.swap(i, end);
    }

    return initialAdvance;
}
예제 #5
0
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
#if OS(WINDOWS)
    // This glyph buffer holds our glyphs + advances + font data for each glyph.
    GlyphBuffer glyphBuffer;

    float startX = point.x();
    UniscribeController controller(this, run);
    controller.advance(from);
    float beforeWidth = controller.runWidthSoFar();
    controller.advance(to, &glyphBuffer);
    
    // We couldn't generate any glyphs for the run.  Give up.
    if (glyphBuffer.isEmpty())
        return;
    
    float afterWidth = controller.runWidthSoFar();

    if (run.rtl()) {
        controller.advance(run.length());
        startX += controller.runWidthSoFar() - afterWidth;
    } else
        startX += beforeWidth;

    // Draw the glyph buffer now at the starting point returned in startX.
    FloatPoint startPoint(startX, point.y());
    drawGlyphBuffer(context, glyphBuffer, run, startPoint);
#else
    notImplemented();
#endif
}
예제 #6
0
UniscribeHelperTextRun::UniscribeHelperTextRun(const TextRun& run,
                                               const Font& font)
    : UniscribeHelper(0, run.length(), run.rtl(),
                      font.primaryFont()->platformData().hfont(),
                      font.primaryFont()->platformData().scriptCache(),
                      font.primaryFont()->platformData().scriptFontProperties(),
                      font.primaryFont()->spaceGlyph())
    , m_font(&font)
    , m_fontIndex(0)
{
    if (run.is8Bit()) {
        m_stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length());
        setInput(m_stringFor8BitRun.characters16());
    } else {
        setInput(run.characters16());
    }

    setDirectionalOverride(run.directionalOverride());
    setLetterSpacing(font.letterSpacing());
    setSpaceWidth(font.spaceWidth());
    setWordSpacing(font.wordSpacing());
    setAscent(font.fontMetrics().ascent());
    setRangeProperties(font.fontDescription().featureSettings());

    init();

    // Expansion is the amount to add to make justification happen. This
    // should be done after Init() so all the runs are already measured.
    if (run.expansion() > 0)
        justify(run.expansion());
}
static void adjustOffsetsForTextDrawing(const TextRun& run, int& from, int& to)
{
    if (run.rtl()) {
        from = run.length() - from;
        to = run.length() - to;
    }
}
예제 #8
0
PassRefPtr<ShapeResult> ShapeResult::createForTabulationCharacters(const Font* font,
    const TextRun& textRun, float positionOffset, unsigned count)
{
    const SimpleFontData* fontData = font->primaryFont();
    OwnPtr<ShapeResult::RunInfo> run = adoptPtr(new ShapeResult::RunInfo(fontData,
        // Tab characters are always LTR or RTL, not TTB, even when isVerticalAnyUpright().
        textRun.rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR,
        HB_SCRIPT_COMMON, 0, count, count));
    float position = textRun.xPos() + positionOffset;
    float startPosition = position;
    for (unsigned i = 0; i < count; i++) {
        float advance = font->tabWidth(*fontData, textRun.getTabSize(), position);
        run->m_glyphData[i].characterIndex = i;
        run->setGlyphAndPositions(i, fontData->spaceGlyph(), advance, 0, 0);
        position += advance;
    }
    run->m_width = position - startPosition;

    RefPtr<ShapeResult> result = ShapeResult::create(font, count, textRun.direction());
    result->m_width = run->m_width;
    result->m_numGlyphs = count;
    ASSERT(result->m_numGlyphs == count); // no overflow
    result->m_hasVerticalOffsets = fontData->platformData().isVerticalAnyUpright();
    result->m_runs.append(run.release());
    return result.release();
}
예제 #9
0
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
                           int from, int to) const
{
    if (to < 0)
        to = run.length();
    if (from < 0)
        from = 0;

    TextRunComponents components;
    int w = generateComponents(&components, *this, run);

    int curPos = 0;
    for (int i = 0; i < (int)components.size(); ++i) {
        const TextRunComponent& comp = components.at(i);
        int len = comp.textLength();
        int curEnd = curPos + len;
        if (curPos < to && from < curEnd && !comp.isSpace()) {
            FloatPoint pt = point;
            if (run.rtl())
                pt.setX(point.x() + w - comp.m_offset - comp.m_width);
            else
                pt.setX(point.x() + comp.m_offset);
            drawSimpleText(context, comp.m_textRun, pt, from - curPos, std::min(to, curEnd) - curPos);
        }
        curPos += len;
        if (from < curPos)
            from = curPos;
    }
}
예제 #10
0
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point,
                           int from, int to) const
{
    // This glyph buffer holds our glyphs + advances + font data for each glyph.
    GlyphBuffer glyphBuffer;

    float startX = point.x();
    CoreTextController controller(this, run);
    controller.advance(from);
    float beforeWidth = controller.runWidthSoFar();
    controller.advance(to, &glyphBuffer);
    
    // We couldn't generate any glyphs for the run.  Give up.
    if (glyphBuffer.isEmpty())
        return;
    
    float afterWidth = controller.runWidthSoFar();

    if (run.rtl()) {
        startX += controller.totalWidth() + controller.finalRoundingWidth() - afterWidth;
        for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
            glyphBuffer.swap(i, end);
    } else
        startX += beforeWidth;

    // Draw the glyph buffer now at the starting point returned in startX.
    FloatPoint startPoint(startX, point.y());
    drawGlyphBuffer(context, glyphBuffer, run, startPoint);
}
예제 #11
0
float Font::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
{
    WidthIterator it(this, run, 0, false, forTextEmphasis);
    GlyphBuffer localGlyphBuffer;
    it.advance(run.length(), &localGlyphBuffer);

    if (localGlyphBuffer.isEmpty())
        return 0;

    float totalWidth = it.m_runWidthSoFar;
    float beforeWidth = 0;
    int glyphPos = 0;
    for (; glyphPos < localGlyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos)
        beforeWidth += localGlyphBuffer.advanceAt(glyphPos).width();
    int glyphFrom = glyphPos;

    float afterWidth = totalWidth;
    glyphPos = localGlyphBuffer.size() - 1;
    for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos)
        afterWidth -= localGlyphBuffer.advanceAt(glyphPos).width();
    int glyphTo = glyphPos + 1;

    glyphBuffer.add(&localGlyphBuffer, glyphFrom, glyphTo - glyphFrom);

    if (run.rtl()) {
        glyphBuffer.reverse(0, glyphBuffer.size());
        return totalWidth - afterWidth;
    }

    return beforeWidth;
}
예제 #12
0
파일: FontWx.cpp 프로젝트: Moondee/Artemis
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
{
#if OS(WINDOWS) || OS(DARWIN)
    ComplexTextController it(this, run);
    it.advance(from);
    float beforeWidth = it.runWidthSoFar();
    it.advance(to);
    float afterWidth = it.runWidthSoFar();

    // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
    if (run.rtl()) {
#if OS(WINDOWS)
        it.advance(run.length());
        float totalWidth = it.runWidthSoFar();
        return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
#else
        float totalWidth = it.totalWidth();
        return FloatRect(point.x() + floorf(totalWidth - afterWidth), point.y(), roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), h);
#endif
    } 
    
    return FloatRect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
#else
    notImplemented();
    return FloatRect();
#endif
}
예제 #13
0
FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
{
    GlyphBuffer glyphBuffer;
    WidthIterator it(this, run);
    it.advance(run.length(), &glyphBuffer);

    float totalWidth = it.m_runWidthSoFar;
    float beforeWidth = 0;
    int glyphPos = 0;
    for (; glyphPos < glyphBuffer.size() && it.m_characterIndexOfGlyph[glyphPos] < from; ++glyphPos)
        beforeWidth += glyphBuffer.advanceAt(glyphPos).width();
    int glyphFrom = glyphPos;

    float afterWidth = totalWidth;
    glyphPos = glyphBuffer.size() - 1;
    for (; glyphPos >= glyphFrom && it.m_characterIndexOfGlyph[glyphPos] >= to; --glyphPos)
        afterWidth -= glyphBuffer.advanceAt(glyphPos).width();

    // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning.
    if (run.rtl()) {
        return FloatRect(floorf(point.x() + totalWidth - afterWidth), point.y(), roundf(point.x() + totalWidth - beforeWidth) - floorf(point.x() + totalWidth - afterWidth), h);
    }

    return FloatRect(floorf(point.x() + beforeWidth), point.y(), roundf(point.x() + afterWidth) - floorf(point.x() + beforeWidth), h);
}
예제 #14
0
int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results,
    const TextRun& run, float targetX)
{
    unsigned totalOffset;
    if (run.rtl()) {
        totalOffset = run.length();
        for (unsigned i = results.size(); i; --i) {
            const RefPtr<ShapeResult>& wordResult = results[i - 1];
            if (!wordResult)
                continue;
            totalOffset -= wordResult->numCharacters();
            if (targetX >= 0 && targetX <= wordResult->width()) {
                int offsetForWord = wordResult->offsetForPosition(targetX);
                return totalOffset + offsetForWord;
            }
            targetX -= wordResult->width();
        }
    } else {
        totalOffset = 0;
        for (auto& wordResult : results) {
            if (!wordResult)
                continue;
            int offsetForWord = wordResult->offsetForPosition(targetX);
            ASSERT(offsetForWord >= 0);
            totalOffset += offsetForWord;
            if (targetX >= 0 && targetX <= wordResult->width())
                return totalOffset;
            targetX -= wordResult->width();
        }
    }
    return totalOffset;
}
예제 #15
0
float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
    GlyphBuffer* glyphBuffer, const TextRun& textRun,
    unsigned from, unsigned to)
{
    float advance = 0;
    if (textRun.rtl()) {
        unsigned wordOffset = textRun.length();
        for (unsigned j = 0; j < results.size(); j++) {
            unsigned resolvedIndex = results.size() - 1 - j;
            RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
                advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
                    wordResult->m_runs[i].get(), advance, from, to,
                    wordOffset - wordResult->numCharacters());
            }
            wordOffset -= wordResult->numCharacters();
        }
    } else {
        unsigned wordOffset = 0;
        for (unsigned j = 0; j < results.size(); j++) {
            RefPtr<ShapeResult>& wordResult = results[j];
            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
                advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
                    wordResult->m_runs[i].get(), advance, from, to, wordOffset);
            }
            wordOffset += wordResult->numCharacters();
        }
    }

    return advance;
}
예제 #16
0
FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
{
    GlyphBuffer glyphBuffer;
    WidthIterator it(this, run);
    it.advance(from, &glyphBuffer);
    float beforeWidth = it.m_runWidthSoFar;
    it.advance(to, &glyphBuffer);
    float afterWidth = it.m_runWidthSoFar;

    // Using roundf() rather than ceilf() for the right edge as a compromise to
    // ensure correct caret positioning.
    // Use LayoutUnit::epsilon() to ensure that values that cannot be stored as
    // an integer are floored to n and not n-1 due to floating point imprecision.
    if (run.rtl()) {
        it.advance(run.length(), &glyphBuffer);
        float totalWidth = it.m_runWidthSoFar;
        float pixelAlignedX = floorf(point.x() + totalWidth - afterWidth + LayoutUnit::epsilon());
        return FloatRect(pixelAlignedX, point.y(),
            roundf(point.x() + totalWidth - beforeWidth) - pixelAlignedX, h);
    }

    float pixelAlignedX = floorf(point.x() + beforeWidth + LayoutUnit::epsilon());
    return FloatRect(pixelAlignedX, point.y(),
        roundf(point.x() + afterWidth) - pixelAlignedX, h);
}
예제 #17
0
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                const IntPoint& point, int h, int from, int to) const
{
    SkPaint              paint;
    SkScalar             width, left;
    SkPaint::FontMetrics metrics;

    primaryFont()->platformData().setupPaint(&paint);

    SkScalar spacing = paint.getFontMetrics(&metrics);

    float beforeWidth = SkScalarToFloat(paint.measureText(run.characters(), from << 1));
    float afterWidth = SkScalarToFloat(paint.measureText(run.characters(), to << 1));

    if (run.rtl()) {
    	float totalWidth = SkScalarToFloat(paint.measureText(run.characters(), run.length() << 1));
    	return FloatRect(point.x() + floorf(totalWidth - afterWidth),
    	                 point.y(),
                         roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth),
    	                 //roundf(SkScalarToFloat(spacing))); // Don't compute rect height, but use h.
                         h);
    } else {
        return FloatRect(point.x() + floorf(beforeWidth),
                         point.y(),
                         roundf(afterWidth) - floorf(beforeWidth),
                         //roundf(SkScalarToFloat(spacing))); // Don't compute rect height, but use h.
                         h);
    }
}
예제 #18
0
FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const
{
    int charsConsumed;
    String glyphName;

    return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName),
                     point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);
}
예제 #19
0
// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const FloatPoint& point, int height,
                                            int from, int to) const
{
    ComplexTextController controller(this, run, 0, 0);
    if (run.rtl())
        controller.setupForRTL();
    return controller.selectionRect(point, height, from, to);
}
예제 #20
0
void ShapeResult::applySpacing(ShapeResultSpacing& spacing,
                               const TextRun& textRun) {
  float offsetX, offsetY;
  float& offset = spacing.isVerticalOffset() ? offsetY : offsetX;
  float totalSpace = 0;
  for (auto& run : m_runs) {
    if (!run)
      continue;
    float totalSpaceForRun = 0;
    for (size_t i = 0; i < run->m_glyphData.size(); i++) {
      HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];

      // Skip if it's not a grapheme cluster boundary.
      if (i + 1 < run->m_glyphData.size() &&
          glyphData.characterIndex == run->m_glyphData[i + 1].characterIndex) {
        // In RTL, marks need the same letter-spacing offset as the base.
        if (textRun.rtl() && spacing.letterSpacing()) {
          offsetX = offsetY = 0;
          offset = spacing.letterSpacing();
          glyphData.offset.expand(offsetX, offsetY);
        }
      } else {
        offsetX = offsetY = 0;
        float space = spacing.computeSpacing(
            textRun, run->m_startIndex + glyphData.characterIndex, offset);
        glyphData.advance += space;
        totalSpaceForRun += space;
        if (textRun.rtl()) {
          // In RTL, spacing should be added to left side of glyphs.
          offset += space;
        }
        glyphData.offset.expand(offsetX, offsetY);
      }
      m_hasVerticalOffsets |= (glyphData.offset.height() != 0);
    }
    run->m_width += totalSpaceForRun;
    totalSpace += totalSpaceForRun;
  }
  m_width += totalSpace;
  if (spacing.isVerticalOffset())
    m_glyphBoundingBox.setHeight(m_glyphBoundingBox.height() + totalSpace);
  else
    m_glyphBoundingBox.setWidth(m_glyphBoundingBox.width() + totalSpace);
}
예제 #21
0
void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
                           const FloatPoint& point, int from, int to) const
{
    if (!run.length())
        return;

    SkCanvas* canvas = gc->platformContext()->canvas();
    TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();
    bool fill = textMode & TextModeFill;
    bool stroke = (textMode & TextModeStroke)
               && gc->platformContext()->getStrokeStyle() != NoStroke
               && gc->platformContext()->getStrokeThickness() > 0;

    if (!fill && !stroke)
        return;

    SkPaint strokePaint, fillPaint;
    if (fill) {
        gc->platformContext()->setupPaintForFilling(&fillPaint);
        setupForTextPainting(&fillPaint, gc->fillColor().rgb());
    }
    if (stroke) {
        gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
        setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
    }

    ComplexTextController controller(run, point.x(), point.y(), this);
    controller.setWordSpacingAdjustment(wordSpacing());
    controller.setLetterSpacingAdjustment(letterSpacing());
    controller.setPadding(run.expansion());

    if (run.rtl()) {
        // FIXME: this causes us to shape the text twice -- once to compute the width and then again
        // below when actually rendering.  Change ComplexTextController to match platform/mac and
        // platform/chromium/win by having it store the shaped runs, so we can reuse the results.
        controller.reset(point.x() + controller.widthOfFullRun());
        // We need to set the padding again because ComplexTextController layout consumed the value.
        // Fixing the above problem would help here too.
        controller.setPadding(run.expansion());
    }

    while (controller.nextScriptRun()) {
        if (fill) {
            controller.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
            adjustTextRenderMode(&fillPaint, gc->platformContext());
            canvas->drawPosText(controller.glyphs(), controller.length() << 1, controller.positions(), fillPaint);
        }

        if (stroke) {
            controller.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
            adjustTextRenderMode(&strokePaint, gc->platformContext());
            canvas->drawPosText(controller.glyphs(), controller.length() << 1, controller.positions(), strokePaint);
        }
    }
}
예제 #22
0
// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
                                          bool includePartialGlyphs) const
{
    // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
    // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
    int targetX = static_cast<int>(xFloat);

    // (Mac code ignores includePartialGlyphs, and they don't know what it's
    // supposed to do, so we just ignore it as well.)
    ComplexTextController controller(run, 0, 0, this);
    controller.setWordSpacingAdjustment(wordSpacing());
    controller.setLetterSpacingAdjustment(letterSpacing());
    controller.setPadding(run.expansion());
    if (run.rtl()) {
        // See FIXME in drawComplexText.
        controller.reset(controller.widthOfFullRun());
        controller.setPadding(run.expansion());
    }

    unsigned basePosition = 0;

    int x = controller.offsetX();
    while (controller.nextScriptRun()) {
        int nextX = controller.offsetX();

        if (std::min(x, nextX) <= targetX && targetX <= std::max(x, nextX)) {
            // The x value in question is within this script run.
            const int glyphIndex = glyphIndexForXPositionInScriptRun(controller, targetX);

            // Now that we have a glyph index, we have to turn that into a
            // code-point index. Because of ligatures, several code-points may
            // have gone into a single glyph. We iterate over the clusters log
            // and find the first code-point which contributed to the glyph.

            // Some shapers (i.e. Khmer) will produce cluster logs which report
            // that /no/ code points contributed to certain glyphs. Because of
            // this, we take any code point which contributed to the glyph in
            // question, or any subsequent glyph. If we run off the end, then
            // we take the last code point.
            const unsigned short* log = controller.logClusters();
            for (unsigned j = 0; j < controller.numCodePoints(); ++j) {
                if (log[j] >= glyphIndex)
                    return basePosition + j;
            }

            return basePosition + controller.numCodePoints() - 1;
        }

        basePosition += controller.numCodePoints();
    }

    return basePosition;
}
예제 #23
0
TextRunComponent::TextRunComponent(const UChar *start, int length, const TextRun& parentTextRun, const Font &font, int o)
    : m_textRun(start, length, parentTextRun.allowTabs(), 0, 0
        , parentTextRun.rtl()
        , parentTextRun.directionalOverride()
        , parentTextRun.applyRunRounding()
        , parentTextRun.applyWordRounding())
    , m_offset(o)
    , m_spaces(0)
{
    WidthIterator it(&font, m_textRun);
    it.advance(m_textRun.length(), 0);
    m_width = it.m_runWidthSoFar;
}
예제 #24
0
float ShapeResult::fillGlyphBufferForTextEmphasis(
    Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
    const TextRun& textRun, const GlyphData* emphasisData,
    unsigned from, unsigned to)
{
    float advance = 0;
    unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
    for (unsigned j = 0; j < results.size(); j++) {
        unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
        RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
        for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
            unsigned resolvedOffset = wordOffset -
                (textRun.rtl() ? wordResult->numCharacters() : 0);
            advance += wordResult->fillGlyphBufferForTextEmphasisRun(
                glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
                advance, from, to, resolvedOffset);
        }
        wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
    }

    return advance;
}
예제 #25
0
// Return the rectangle for selecting the given range of code-points in the TextRun.
FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                            const FloatPoint& point, int height,
                                            int from, int to) const
{
    int fromX = -1, toX = -1;
    ComplexTextController controller(run, 0, 0, this);
    controller.setWordSpacingAdjustment(wordSpacing());
    controller.setLetterSpacingAdjustment(letterSpacing());
    controller.setPadding(run.expansion());
    if (run.rtl()) {
        // See FIXME in drawComplexText.
        controller.reset(controller.widthOfFullRun());
        controller.setPadding(run.expansion());
    }

    // Iterate through the script runs in logical order, searching for the run covering the positions of interest.
    while (controller.nextScriptRun() && (fromX == -1 || toX == -1)) {
        if (fromX == -1 && from >= 0 && static_cast<unsigned>(from) < controller.numCodePoints()) {
            // |from| is within this script run. So we index the clusters log to
            // find which glyph this code-point contributed to and find its x
            // position.
            int glyph = controller.logClusters()[from];
            fromX = controller.positions()[glyph].x();
            if (controller.rtl())
                fromX += truncateFixedPointToInteger(controller.advances()[glyph]);
        } else
            from -= controller.numCodePoints();

        if (toX == -1 && to >= 0 && static_cast<unsigned>(to) < controller.numCodePoints()) {
            int glyph = controller.logClusters()[to];
            toX = controller.positions()[glyph].x();
            if (controller.rtl())
                toX += truncateFixedPointToInteger(controller.advances()[glyph]);
        } else
            to -= controller.numCodePoints();
    }

    // The position in question might be just after the text.
    if (fromX == -1)
        fromX = controller.offsetX();
    if (toX == -1)
        toX = controller.offsetX();

    ASSERT(fromX != -1 && toX != -1);

    if (fromX < toX)
        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);

    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
}
예제 #26
0
void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
                           const FloatPoint& point, int from, int to) const
{
    if (!run.length())
        return;

    SkCanvas* canvas = gc->platformContext()->canvas();
    TextDrawingModeFlags textMode = gc->platformContext()->getTextDrawingMode();
    bool fill = textMode & TextModeFill;
    bool stroke = (textMode & TextModeStroke)
               && gc->platformContext()->getStrokeStyle() != NoStroke
               && gc->platformContext()->getStrokeThickness() > 0;

    if (!fill && !stroke)
        return;

    SkPaint strokePaint, fillPaint;
    if (fill) {
        gc->platformContext()->setupPaintForFilling(&fillPaint);
        setupForTextPainting(&fillPaint, gc->fillColor().rgb());
    }
    if (stroke) {
        gc->platformContext()->setupPaintForStroking(&strokePaint, 0, 0);
        setupForTextPainting(&strokePaint, gc->strokeColor().rgb());
    }

    ComplexTextController controller(this, run, point.x(), point.y());
    if (run.rtl())
        controller.setupForRTL();

    while (controller.nextScriptRun()) {
        // Check if there is any glyph found in the current script run.
        int fromGlyph, glyphLength;
        controller.glyphsForRange(from, to, fromGlyph, glyphLength);
        if (fromGlyph < 0 || glyphLength <= 0)
            continue;

        if (fill) {
            controller.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
            adjustTextRenderMode(&fillPaint, gc->platformContext());
            canvas->drawPosText(controller.glyphs() + fromGlyph, glyphLength << 1, controller.positions() + fromGlyph, fillPaint);
        }

        if (stroke) {
            controller.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
            adjustTextRenderMode(&strokePaint, gc->platformContext());
            canvas->drawPosText(controller.glyphs() + fromGlyph, glyphLength << 1, controller.positions() + fromGlyph, strokePaint);
        }
    }
}
예제 #27
0
static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
{
    int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
    if (style.padding())
        flags |= Qt::TextJustificationForced;
    layout->setFlags(flags);
    layout->beginLayout();
    QTextLine line = layout->createLine();
    line.setLineWidth(INT_MAX/256);
    if (style.padding())
        line.setLineWidth(line.naturalTextWidth() + style.padding());
    layout->endLayout();
    return line;
}
예제 #28
0
// Return the code point index for the given |x| offset into the text run.
int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat,
                                          bool includePartialGlyphs) const
{
    // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
    // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
    int targetX = static_cast<int>(xFloat);

    // (Mac code ignores includePartialGlyphs, and they don't know what it's
    // supposed to do, so we just ignore it as well.)
    ComplexTextController controller(this, run, 0, 0);
    if (run.rtl())
        controller.setupForRTL();
    return controller.offsetForPosition(targetX);
}
예제 #29
0
void FontCascade::adjustSelectionRectForComplexText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
{
    UniscribeController it(this, run);
    it.advance(from);
    float beforeWidth = it.runWidthSoFar();
    it.advance(to);
    float afterWidth = it.runWidthSoFar();

    if (run.rtl()) {
        it.advance(run.length());
        selectionRect.move(it.runWidthSoFar() - afterWidth, 0);
    } else
        selectionRect.move(beforeWidth, 0);
    selectionRect.setWidth(afterWidth - beforeWidth);
}
예제 #30
0
FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt,
                                     int h, int from, int to) const
{
    TextRunComponents components;
    int w = generateComponents(&components, *this, run);

    if (!from && to == run.length())
        return FloatRect(pt.x(), pt.y(), w, h);

    float x1 = cursorToX(this, components, w, run.rtl(), from);
    float x2 = cursorToX(this, components, w, run.rtl(), to);
    if (x2 < x1)
        std::swap(x1, x2);

    return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
}