Esempio n. 1
0
void Font::drawGlyphs(GraphicsContext* graphicsContext,
                      const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,
                      int from,
                      int numGlyphs,
                      const FloatPoint& point) const
{
    SkColor color = graphicsContext->platformContext()->effectiveFillColor();
    unsigned char alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke && !graphicsContext->hasShadow())
        return;

    // We draw the glyphs in chunks to avoid having to do a heap allocation for
    // the arrays of characters and advances.
    const int kMaxBufferLength = 256;
    Vector<WORD, kMaxBufferLength> glyphs;
    Vector<int, kMaxBufferLength> advances;
    int glyphIndex = 0;  // The starting glyph of the current chunk.

    // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position
    // of each glyph in floating point units and rounds to integer advances at the last possible moment.

    float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph.
    int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered.
    while (glyphIndex < numGlyphs) {
        // How many chars will be in this chunk?
        int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
        glyphs.resize(curLen);
        advances.resize(curLen);

        float currentWidth = 0;
        for (int i = 0; i < curLen; ++i, ++glyphIndex) {
            glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
            horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex);
            advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded;
            lastHorizontalOffsetRounded += advances[i];
            currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            
            // Bug 26088 - very large positive or negative runs can fail to
            // render so we clamp the size here. In the specs, negative
            // letter-spacing is implementation-defined, so this should be
            // fine, and it matches Safari's implementation. The call actually
            // seems to crash if kMaxNegativeRun is set to somewhere around
            // -32830, so we give ourselves a little breathing room.
            const int maxNegativeRun = -32768;
            const int maxPositiveRun =  32768;
            if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) 
                advances[i] = 0;
        }

        SkPoint origin = point;
        origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth);
        paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin);
    }
}
Esempio n. 2
0
void paintSkiaText(GraphicsContext* context,
                   const FontPlatformData& data,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint* origin)
{
    paintSkiaText(context, data.hfont(), data.typeface(), data.size(), data.lfQuality(),
                  numGlyphs, glyphs, advances, offsets, origin);
}
void paintSkiaText(GraphicsContext* context,
                   const FontPlatformData& data,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint& origin,
                   const SkRect& textRect)
{
    paintSkiaText(context, data.hfont(), data.typeface(), data.size(), data.paintTextFlags(),
                  numGlyphs, glyphs, advances, offsets, origin, textRect);
}
void paintSkiaText(GraphicsContext* context,
                   HFONT hfont,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint& origin,
                   const SkRect& textRect)
{
    int size;
    int paintTextFlags;
    RefPtr<SkTypeface> face = CreateTypefaceFromHFont(hfont, &size, &paintTextFlags);
    paintSkiaText(context, hfont, face.get(), size, paintTextFlags, numGlyphs, glyphs, advances, offsets, origin, textRect);
}
Esempio n. 5
0
void paintSkiaText(GraphicsContext* context,
                   HFONT hfont,
                   int numGlyphs,
                   const WORD* glyphs,
                   const int* advances,
                   const GOFFSET* offsets,
                   const SkPoint* origin)
{
    int size;
    int quality;
    SkTypeface* face = CreateTypefaceFromHFont(hfont, &size, &quality);
    SkAutoUnref aur(face);

    paintSkiaText(context, hfont, face, size, quality, numGlyphs, glyphs, advances, offsets, origin);
}
Esempio n. 6
0
void Font::drawGlyphs(GraphicsContext* graphicsContext,
                      const SimpleFontData* font,
                      const GlyphBuffer& glyphBuffer,
                      int from,
                      int numGlyphs,
                      const FloatPoint& point) const
{
    SkColor color = graphicsContext->effectiveFillColor();
    unsigned char alpha = SkColorGetA(color);
    // Skip 100% transparent text; no need to draw anything.
    if (!alpha && graphicsContext->strokeStyle() == NoStroke && !graphicsContext->hasShadow())
        return;

    // We draw the glyphs in chunks to avoid having to do a heap allocation for
    // the arrays of characters and advances.
    const int kMaxBufferLength = 256;
    Vector<int, kMaxBufferLength> advances;
    int glyphIndex = 0;  // The starting glyph of the current chunk.

    float horizontalOffset = point.x(); // The floating point offset of the left side of the current glyph.
#if ENABLE(OPENTYPE_VERTICAL)
    const OpenTypeVerticalData* verticalData = font->verticalData();
    if (verticalData) {
        Vector<FloatPoint, kMaxBufferLength> translations;
        Vector<GOFFSET, kMaxBufferLength> offsets;

        // Skia doesn't have matrix for glyph coordinate space, so we rotate back the CTM.
        AffineTransform savedMatrix = graphicsContext->getCTM();
        graphicsContext->concatCTM(AffineTransform(0, -1, 1, 0, point.x(), point.y()));
        graphicsContext->concatCTM(AffineTransform(1, 0, 0, 1, -point.x(), -point.y()));

        const FontMetrics& metrics = font->fontMetrics();
        SkScalar verticalOriginX = SkFloatToScalar(point.x() + metrics.floatAscent() - metrics.floatAscent(IdeographicBaseline));
        while (glyphIndex < numGlyphs) {
            // How many chars will be in this chunk?
            int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);

            const Glyph* glyphs = glyphBuffer.glyphs(from + glyphIndex);
            translations.resize(curLen);
            verticalData->getVerticalTranslationsForGlyphs(font, &glyphs[0], curLen, reinterpret_cast<float*>(&translations[0]));
            // To position glyphs vertically, we use offsets instead of advances.
            advances.resize(curLen);
            advances.fill(0);
            offsets.resize(curLen);
            float currentWidth = 0;
            for (int i = 0; i < curLen; ++i, ++glyphIndex) {
                offsets[i].du = lroundf(translations[i].x());
                offsets[i].dv = -lroundf(currentWidth - translations[i].y());
                currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            }
            SkPoint origin;
            origin.set(verticalOriginX, SkFloatToScalar(point.y() + horizontalOffset - point.x()));
            horizontalOffset += currentWidth;
            paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], &offsets[0], &origin);
        }

        graphicsContext->setCTM(savedMatrix);
        return;
    }
#endif

    // In order to round all offsets to the correct pixel boundary, this code keeps track of the absolute position
    // of each glyph in floating point units and rounds to integer advances at the last possible moment.

    int lastHorizontalOffsetRounded = lroundf(horizontalOffset); // The rounded offset of the left side of the last glyph rendered.
    Vector<WORD, kMaxBufferLength> glyphs;
    while (glyphIndex < numGlyphs) {
        // How many chars will be in this chunk?
        int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
        glyphs.resize(curLen);
        advances.resize(curLen);

        float currentWidth = 0;
        for (int i = 0; i < curLen; ++i, ++glyphIndex) {
            glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
            horizontalOffset += glyphBuffer.advanceAt(from + glyphIndex);
            advances[i] = lroundf(horizontalOffset) - lastHorizontalOffsetRounded;
            lastHorizontalOffsetRounded += advances[i];
            currentWidth += glyphBuffer.advanceAt(from + glyphIndex);
            
            // Bug 26088 - very large positive or negative runs can fail to
            // render so we clamp the size here. In the specs, negative
            // letter-spacing is implementation-defined, so this should be
            // fine, and it matches Safari's implementation. The call actually
            // seems to crash if kMaxNegativeRun is set to somewhere around
            // -32830, so we give ourselves a little breathing room.
            const int maxNegativeRun = -32768;
            const int maxPositiveRun =  32768;
            if ((currentWidth + advances[i] < maxNegativeRun) || (currentWidth + advances[i] > maxPositiveRun)) 
                advances[i] = 0;
        }

        SkPoint origin = point;
        origin.fX += SkFloatToScalar(horizontalOffset - point.x() - currentWidth);
        paintSkiaText(graphicsContext, font->platformData(), curLen, &glyphs[0], &advances[0], 0, &origin);
    }
}
void UniscribeHelper::draw(GraphicsContext* graphicsContext,
                           HDC dc, int x, int y, int from, int to)
{
    HGDIOBJ oldFont = 0;
    int curX = x;
    bool firstRun = true;
    bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);

    for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
        int itemIndex = m_screenOrder[screenIndex];
        const SCRIPT_ITEM& item = m_runs[itemIndex];
        const Shaping& shaping = m_shapes[itemIndex];

        // Character offsets within this run. THESE MAY NOT BE IN RANGE and may
        // be negative, etc. The code below handles this.
        int fromChar = from - item.iCharPos;
        int toChar = to - item.iCharPos;

        // See if we need to draw any characters in this item.
        if (shaping.charLength() == 0 ||
            fromChar >= shaping.charLength() || toChar <= 0) {
            // No chars in this item to display.
            curX += advanceForItem(itemIndex);
            continue;
        }

        // Compute the starting glyph within this span. |from| and |to| are
        // global offsets that may intersect arbitrarily with our local run.
        int fromGlyph, afterGlyph;
        if (item.a.fRTL) {
            // To compute the first glyph when going RTL, we use |to|.
            if (toChar >= shaping.charLength())
                // The end of the text is after (to the left) of us.
                fromGlyph = 0;
            else {
                // Since |to| is exclusive, the first character we draw on the
                // left is actually the one right before (to the right) of
                // |to|.
                fromGlyph = shaping.m_logs[toChar - 1];
            }

            // The last glyph is actually the first character in the range.
            if (fromChar <= 0) {
                // The first character to draw is before (to the right) of this
                // span, so draw all the way to the end.
                afterGlyph = shaping.glyphLength();
            } else {
                // We want to draw everything up until the character to the
                // right of |from|. To the right is - 1, so we look that up
                // (remember our character could be more than one glyph, so we
                // can't look up our glyph and add one).
                afterGlyph = shaping.m_logs[fromChar - 1];
            }
        } else {
            // Easy case, everybody agrees about directions. We only need to
            // handle boundary conditions to get a range inclusive at the
            // beginning, and exclusive at the ending. We have to do some
            // computation to see the glyph one past the end.
            fromGlyph = shaping.m_logs[fromChar < 0 ? 0 : fromChar];
            if (toChar >= shaping.charLength())
                afterGlyph = shaping.glyphLength();
            else
                afterGlyph = shaping.m_logs[toChar];
        }

        // Account for the characters that were skipped in this run. When
        // WebKit asks us to draw a subset of the run, it actually tells us
        // to draw at the X offset of the beginning of the run, since it
        // doesn't know the internal position of any of our characters.
        const int* effectiveAdvances = shaping.effectiveAdvances();
        int innerOffset = 0;
        for (int i = 0; i < fromGlyph; i++)
            innerOffset += effectiveAdvances[i];

        // Actually draw the glyphs we found.
        int glyphCount = afterGlyph - fromGlyph;
        if (fromGlyph >= 0 && glyphCount > 0) {
            // Account for the preceding space we need to add to this run. We
            // don't need to count for the following space because that will be
            // counted in advanceForItem below when we move to the next run.
            innerOffset += shaping.m_prePadding;

            // Pass 0 in when there is no justification.
            const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];

            if (useWindowsDrawing) {
                if (firstRun) {
                    oldFont = SelectObject(dc, shaping.m_hfont);
                    firstRun = false;
                } else
                    SelectObject(dc, shaping.m_hfont);
            }

            // Fonts with different ascents can be used to render different
            // runs.  'Across-runs' y-coordinate correction needs to be
            // adjusted for each font.
            bool textOutOk = false;
            for (int executions = 0; executions < 2; ++executions) {
                if (useWindowsDrawing) {
                    HRESULT hr = ScriptTextOut(dc, shaping.m_scriptCache,
                                               curX + innerOffset,
                                               y - shaping.m_ascentOffset,
                                               0, 0, &item.a, 0, 0,
                                               &shaping.m_glyphs[fromGlyph],
                                               glyphCount,
                                               &shaping.m_advance[fromGlyph],
                                               justify,
                                               &shaping.m_offsets[fromGlyph]);
                    ASSERT(S_OK == hr);
                    textOutOk = (hr == S_OK);
                } else {
                    SkPoint origin;
                    origin.fX = curX + + innerOffset;
                    origin.fY = y + m_ascent;
                    textOutOk = paintSkiaText(graphicsContext,
                                              shaping.m_hfont,
                                              glyphCount,
                                              &shaping.m_glyphs[fromGlyph],
                                              &shaping.m_advance[fromGlyph],
                                              &shaping.m_offsets[fromGlyph],
                                              &origin);
                }

                if (!textOutOk && 0 == executions) {
                    // If TextOut is called from the renderer it might fail
                    // because the sandbox is preventing it from opening the
                    // font files.  If we are running in the renderer,
                    // TryToPreloadFont is overridden to ask the browser to
                    // preload the font for us so we can access it.
                    tryToPreloadFont(shaping.m_hfont);
                    continue;
                }
                break;
            }
        }

        curX += advanceForItem(itemIndex);
    }

    if (oldFont)
        SelectObject(dc, oldFont);
}