Beispiel #1
0
void Font::drawComplexText(GraphicsContext* graphicsContext,
                           const TextRun& run,
                           const FloatPoint& point,
                           int from,
                           int to) const
{
    PlatformGraphicsContext* context = graphicsContext->platformContext();
    UniscribeHelperTextRun state(run, *this);

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

#if USE(SKIA_TEXT)
    HDC hdc = 0;
#else
    TransparencyAwareUniscribePainter painter(graphicsContext, this, run, from, to, point);

    HDC hdc = painter.hdc();
    if (windowsCanHandleTextDrawing(graphicsContext) && !hdc)
        return;

    // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
    // Enforce non-transparent color.
    color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
    if (hdc) {
        SetTextColor(hdc, skia::SkColorToCOLORREF(color));
        SetBkMode(hdc, TRANSPARENT);
    }

    // If there is a non-blur shadow and both the fill color and shadow color 
    // are opaque, handle without skia. 
    FloatSize shadowOffset;
    float shadowBlur;
    Color shadowColor;
    ColorSpace shadowColorSpace;
    if (graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace) && windowsCanHandleDrawTextShadow(graphicsContext)) {
        COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
        COLORREF savedTextColor = GetTextColor(hdc);
        SetTextColor(hdc, textColor);
        state.draw(graphicsContext, hdc, static_cast<int>(point.x()) + shadowOffset.width(),
                   static_cast<int>(point.y() - fontMetrics().ascent()) + shadowOffset.height(), from, to);
        SetTextColor(hdc, savedTextColor); 
    }
#endif
    // Uniscribe counts the coordinates from the upper left, while WebKit uses
    // the baseline, so we have to subtract off the ascent.
    state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to);
}
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);
}