Title: [97149] trunk
Revision
97149
Author
r...@google.com
Date
2011-10-11 06:11:33 -0700 (Tue, 11 Oct 2011)

Log Message

re-add support for GDI text behind a compile flag
https://bugs.webkit.org/show_bug.cgi?id=69530

Reviewed by James Robinson.

Source/WebCore:

Reverts back to using GDI for text (when possible)
but keeps skia-text version behind a compile-flag. If/when we can
resolve the outstanding soft-clip and intl-performance bugs with the
skia version, we may change the compile-flag to reenable skia.

Previous change http://trac.webkit.org/changeset/94589 removed the GDI code.

* platform/graphics/chromium/FontChromiumWin.cpp:
(WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::TransparencyAwareFontPainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::init):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::initializeForGDI):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::~TransparencyAwareFontPainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::estimateTextBounds):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::drawGlyphs):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::hdc):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter):
(WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::estimateTextBounds):
(WebCore::drawGlyphsWin):
(WebCore::Font::drawGlyphs):
(WebCore::Font::drawComplexText):
* platform/graphics/chromium/UniscribeHelper.cpp:
(WebCore::UniscribeHelper::draw):
* platform/graphics/skia/PlatformContextSkia.cpp:
(WebCore::PlatformContextSkia::isNativeFontRenderingAllowed):
* platform/graphics/skia/PlatformContextSkia.h:
* platform/graphics/skia/SkiaFontWin.cpp:
(WebCore::windowsCanHandleDrawTextShadow):
(WebCore::windowsCanHandleTextDrawing):
(WebCore::windowsCanHandleTextDrawingWithoutShadow):
* platform/graphics/skia/SkiaFontWin.h:

Source/WebKit/chromium:

* features.gypi:

LayoutTests:

* platform/chromium/test_expectations.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (97148 => 97149)


--- trunk/LayoutTests/ChangeLog	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/LayoutTests/ChangeLog	2011-10-11 13:11:33 UTC (rev 97149)
@@ -1,3 +1,12 @@
+2011-10-11  Mike Reed  <r...@google.com>
+
+        re-add support for GDI text behind a compile flag
+        https://bugs.webkit.org/show_bug.cgi?id=69530
+
+        Reviewed by James Robinson.
+
+        * platform/chromium/test_expectations.txt:
+
 2011-10-11  Jer Noble  <jer.no...@apple.com>
 
         REGRESSION (r96770-r96777): fast/dom/Window/window-properties.html, fast/dom/prototype-inheritance-2.html, fast/js/global-constructors.html failing on SnowLeopard Intel Release (Tests)

Modified: trunk/LayoutTests/platform/chromium/test_expectations.txt (97148 => 97149)


--- trunk/LayoutTests/platform/chromium/test_expectations.txt	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/LayoutTests/platform/chromium/test_expectations.txt	2011-10-11 13:11:33 UTC (rev 97149)
@@ -1415,6 +1415,14 @@
 // This test also started failing with the merge of March 25th 2009
 BUGCR10441 MAC WIN : transitions/transition-end-event-transform.html = PASS TEXT
 
+// Disable these while we're back to using GDI for text drawing. These give slightly
+// different results than with Skia. When we switch back to Skia, we can
+// reenable these.
+BUGCR99500 WIN : media/audio-repaint.html = IMAGE
+BUGCR99500 WIN : svg/as-background-image/animated-svg-as-background.html = IMAGE
+BUGCR99500 WIN : svg/batik/text/textStyles.svg = IMAGE
+BUGCR99500 WIN : svg/custom/simple-text-double-shadow.svg = IMAGE
+
 // Merge 41768:41807
 // Perhaps just needs new baseline?
 // These tests were rebaselined with failure long ago. We shouldn't do this, and
@@ -2104,7 +2112,6 @@
 
 // On XP, some glyphs show subpixel antialiasing when they shouldn't
 BUGWK65203 XP : fast/text/international/bidi-mirror-he-ar.html = IMAGE
-BUGWK65203 XP : svg/batik/text/textStyles.svg = IMAGE
 
 BUGWK42428 LINUX WIN : svg/W3C-SVG-1.1/filters-conv-01-f.svg = IMAGE+TEXT
 

Modified: trunk/Source/WebCore/ChangeLog (97148 => 97149)


--- trunk/Source/WebCore/ChangeLog	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/ChangeLog	2011-10-11 13:11:33 UTC (rev 97149)
@@ -1,3 +1,44 @@
+2011-10-11  Mike Reed  <r...@google.com>
+
+        re-add support for GDI text behind a compile flag
+        https://bugs.webkit.org/show_bug.cgi?id=69530
+
+        Reviewed by James Robinson.
+
+        Reverts back to using GDI for text (when possible)
+        but keeps skia-text version behind a compile-flag. If/when we can
+        resolve the outstanding soft-clip and intl-performance bugs with the
+        skia version, we may change the compile-flag to reenable skia.
+        
+        Previous change http://trac.webkit.org/changeset/94589 removed the GDI code.
+
+        * platform/graphics/chromium/FontChromiumWin.cpp:
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::TransparencyAwareFontPainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::init):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::initializeForGDI):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareFontPainter::~TransparencyAwareFontPainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::estimateTextBounds):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareGlyphPainter::drawGlyphs):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::hdc):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter):
+        (WebCore::TransparencyAwareFontPainter::TransparencyAwareUniscribePainter::estimateTextBounds):
+        (WebCore::drawGlyphsWin):
+        (WebCore::Font::drawGlyphs):
+        (WebCore::Font::drawComplexText):
+        * platform/graphics/chromium/UniscribeHelper.cpp:
+        (WebCore::UniscribeHelper::draw):
+        * platform/graphics/skia/PlatformContextSkia.cpp:
+        (WebCore::PlatformContextSkia::isNativeFontRenderingAllowed):
+        * platform/graphics/skia/PlatformContextSkia.h:
+        * platform/graphics/skia/SkiaFontWin.cpp:
+        (WebCore::windowsCanHandleDrawTextShadow):
+        (WebCore::windowsCanHandleTextDrawing):
+        (WebCore::windowsCanHandleTextDrawingWithoutShadow):
+        * platform/graphics/skia/SkiaFontWin.h:
+
 2011-10-11  Tor Arne Vestbø  <tor.arne.ves...@nokia.com>
 
         [Qt] Remove all references to QTDIR_build and standalone_package

Modified: trunk/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/chromium/FontChromiumWin.cpp	2011-10-11 13:11:33 UTC (rev 97149)
@@ -41,10 +41,335 @@
 #include "SkiaFontWin.h"
 #include "UniscribeHelperTextRun.h"
 
+#if !ENABLE(SKIA_TEXT)
+#include "TransparencyWin.h"
+#include "skia/ext/skia_utils_win.h"
+#endif
+
 #include <windows.h>
 
+using namespace std;
+
 namespace WebCore {
 
+#if !ENABLE(SKIA_TEXT)
+namespace {
+
+bool canvasHasMultipleLayers(const SkCanvas* canvas)
+{
+    SkCanvas::LayerIter iter(const_cast<SkCanvas*>(canvas), false);
+    iter.next(); // There is always at least one layer.
+    return !iter.done(); // There is > 1 layer if the the iterator can stil advance.
+}
+
+class TransparencyAwareFontPainter {
+public:
+    TransparencyAwareFontPainter(GraphicsContext*, const FloatPoint&);
+    ~TransparencyAwareFontPainter();
+
+protected:
+    // Called by our subclass' constructor to initialize GDI if necessary. This
+    // is a separate function so it can be called after the subclass finishes
+    // construction (it calls virtual functions).
+    void init();
+
+    virtual IntRect estimateTextBounds() = 0;
+
+    // Use the context from the transparency helper when drawing with GDI. It
+    // may point to a temporary one.
+    GraphicsContext* m_graphicsContext;
+    PlatformGraphicsContext* m_platformContext;
+
+    FloatPoint m_point;
+
+    // Set when Windows can handle the type of drawing we're doing.
+    bool m_useGDI;
+
+    // These members are valid only when m_useGDI is set.
+    HDC m_hdc;
+    TransparencyWin m_transparency;
+
+private:
+    // Call when we're using GDI mode to initialize the TransparencyWin to help
+    // us draw GDI text.
+    void initializeForGDI();
+
+    bool m_createdTransparencyLayer; // We created a layer to give the font some alpha.
+};
+
+TransparencyAwareFontPainter::TransparencyAwareFontPainter(GraphicsContext* context,
+                                                           const FloatPoint& point)
+    : m_graphicsContext(context)
+    , m_platformContext(context->platformContext())
+    , m_point(point)
+    , m_useGDI(windowsCanHandleTextDrawing(context))
+    , m_hdc(0)
+    , m_createdTransparencyLayer(false)
+{
+}
+
+void TransparencyAwareFontPainter::init()
+{
+    if (m_useGDI)
+        initializeForGDI();
+}
+
+void TransparencyAwareFontPainter::initializeForGDI()
+{
+    m_graphicsContext->save();
+    SkColor color = m_platformContext->effectiveFillColor();
+    // Used only when m_createdTransparencyLayer is true.
+    float layerAlpha = 0.0f;
+    if (SkColorGetA(color) != 0xFF) {
+        // When the font has some transparency, apply it by creating a new
+        // transparency layer with that opacity applied. We'll actually create
+        // a new transparency layer after we calculate the bounding box.
+        m_createdTransparencyLayer = true;
+        layerAlpha = SkColorGetA(color) / 255.0f;
+        // The color should be opaque now.
+        color = SkColorSetRGB(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color));
+    }
+
+    TransparencyWin::LayerMode layerMode;
+    IntRect layerRect;
+    if (m_platformContext->isDrawingToImageBuffer()) {
+        // Assume if we're drawing to an image buffer that the background
+        // is not opaque and we have to undo ClearType. We may want to
+        // enhance this to actually check, since it will often be opaque
+        // and we could do ClearType in that case.
+        layerMode = TransparencyWin::TextComposite;
+        layerRect = estimateTextBounds();
+        m_graphicsContext->clip(layerRect);
+        if (m_createdTransparencyLayer)
+            m_graphicsContext->beginTransparencyLayer(layerAlpha);
+
+        // The transparency helper requires that we draw text in black in
+        // this mode and it will apply the color.
+        m_transparency.setTextCompositeColor(color);
+        color = SkColorSetRGB(0, 0, 0);
+    } else if (m_createdTransparencyLayer || canvasHasMultipleLayers(m_platformContext->canvas())) {
+        // When we're drawing a web page, we know the background is opaque,
+        // but if we're drawing to a layer, we still need extra work.
+        layerMode = TransparencyWin::OpaqueCompositeLayer;
+        layerRect = estimateTextBounds();
+        m_graphicsContext->clip(layerRect);
+        if (m_createdTransparencyLayer)
+            m_graphicsContext->beginTransparencyLayer(layerAlpha);
+    } else {
+        // Common case of drawing onto the bottom layer of a web page: we
+        // know everything is opaque so don't need to do anything special.
+        layerMode = TransparencyWin::NoLayer;
+    }
+
+    // Bug 26088 - init() might fail if layerRect is invalid. Given this, we
+    // need to be careful to check for null pointers everywhere after this call
+    m_transparency.init(m_graphicsContext, layerMode, 
+                        TransparencyWin::KeepTransform, layerRect);
+
+    // Set up the DC, using the one from the transparency helper.
+    if (m_transparency.platformContext()) {
+        m_hdc = skia::BeginPlatformPaint(m_transparency.platformContext()->canvas());
+        SetTextColor(m_hdc, skia::SkColorToCOLORREF(color));
+        SetBkMode(m_hdc, TRANSPARENT);
+    }
+}
+
+TransparencyAwareFontPainter::~TransparencyAwareFontPainter()
+{
+    if (!m_useGDI || !m_graphicsContext || !m_platformContext)
+        return;
+    m_transparency.composite();
+    if (m_createdTransparencyLayer)
+        m_graphicsContext->endTransparencyLayer();
+    m_graphicsContext->restore();
+    if (m_transparency.platformContext())
+        skia::EndPlatformPaint(m_transparency.platformContext()->canvas());
+}
+
+// Specialization for simple GlyphBuffer painting.
+class TransparencyAwareGlyphPainter : public TransparencyAwareFontPainter {
+ public:
+    TransparencyAwareGlyphPainter(GraphicsContext*,
+                                  const SimpleFontData*,
+                                  const GlyphBuffer&,
+                                  int from, int numGlyphs,
+                                  const FloatPoint&);
+    ~TransparencyAwareGlyphPainter();
+
+    // Draws the partial string of glyphs, starting at |startAdvance| to the
+    // left of m_point. We express it this way so that if we're using the Skia
+    // drawing path we can use floating-point positioning, even though we have
+    // to use integer positioning in the GDI path.
+    bool drawGlyphs(int numGlyphs, const WORD* glyphs, const int* advances, float startAdvance) const;
+
+ private:
+    virtual IntRect estimateTextBounds();
+
+    const SimpleFontData* m_font;
+    const GlyphBuffer& m_glyphBuffer;
+    int m_from;
+    int m_numGlyphs;
+
+    // When m_useGdi is set, this stores the previous HFONT selected into the
+    // m_hdc so we can restore it.
+    HGDIOBJ m_oldFont; // For restoring the DC to its original state.
+};
+
+TransparencyAwareGlyphPainter::TransparencyAwareGlyphPainter(
+    GraphicsContext* context,
+    const SimpleFontData* font,
+    const GlyphBuffer& glyphBuffer,
+    int from, int numGlyphs,
+    const FloatPoint& point)
+    : TransparencyAwareFontPainter(context, point)
+    , m_font(font)
+    , m_glyphBuffer(glyphBuffer)
+    , m_from(from)
+    , m_numGlyphs(numGlyphs)
+    , m_oldFont(0)
+{
+    init();
+
+    if (m_hdc)
+        m_oldFont = ::SelectObject(m_hdc, m_font->platformData().hfont());
+}
+
+TransparencyAwareGlyphPainter::~TransparencyAwareGlyphPainter()
+{
+    if (m_useGDI && m_hdc)
+        ::SelectObject(m_hdc, m_oldFont);
+}
+
+
+// Estimates the bounding box of the given text. This is copied from
+// FontCGWin.cpp, it is possible, but a lot more work, to get the precide
+// bounds.
+IntRect TransparencyAwareGlyphPainter::estimateTextBounds()
+{
+    int totalWidth = 0;
+    for (int i = 0; i < m_numGlyphs; i++)
+        totalWidth += lroundf(m_glyphBuffer.advanceAt(m_from + i));
+
+    const FontMetrics& fontMetrics = m_font->fontMetrics();
+    return IntRect(m_point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2,
+                   m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
+                   totalWidth + fontMetrics.ascent() + fontMetrics.descent(),
+                   fontMetrics.lineSpacing()); 
+}
+
+bool TransparencyAwareGlyphPainter::drawGlyphs(int numGlyphs,
+                                               const WORD* glyphs,
+                                               const int* advances,
+                                               float startAdvance) const
+{
+    if (!m_useGDI) {
+        SkPoint origin = m_point;
+        origin.fX += SkFloatToScalar(startAdvance);
+        paintSkiaText(m_graphicsContext, m_font->platformData().hfont(),
+                      numGlyphs, glyphs, advances, 0, &origin);
+        return true;
+    }
+
+    if (!m_graphicsContext || !m_hdc)
+        return true;
+
+    // Windows' origin is the top-left of the bounding box, so we have
+    // to subtract off the font ascent to get it.
+    int x = lroundf(m_point.x() + startAdvance);
+    int y = lroundf(m_point.y() - m_font->fontMetrics().ascent());
+
+    // 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 (m_graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)) {
+        // If there is a shadow and this code is reached, windowsCanHandleDrawTextShadow()
+        // will have already returned true during the ctor initiatization of m_useGDI
+        ASSERT(shadowColor.alpha() == 255);
+        ASSERT(m_graphicsContext->fillColor().alpha() == 255);
+        ASSERT(!shadowBlur);
+        COLORREF textColor = skia::SkColorToCOLORREF(SkColorSetARGB(255, shadowColor.red(), shadowColor.green(), shadowColor.blue()));
+        COLORREF savedTextColor = GetTextColor(m_hdc);
+        SetTextColor(m_hdc, textColor);
+        ExtTextOut(m_hdc, x + shadowOffset.width(), y + shadowOffset.height(), ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+        SetTextColor(m_hdc, savedTextColor);
+    }
+    
+    return !!ExtTextOut(m_hdc, x, y, ETO_GLYPH_INDEX, 0, reinterpret_cast<const wchar_t*>(&glyphs[0]), numGlyphs, &advances[0]);
+}
+
+class TransparencyAwareUniscribePainter : public TransparencyAwareFontPainter {
+ public:
+    TransparencyAwareUniscribePainter(GraphicsContext*,
+                                      const Font*,
+                                      const TextRun&,
+                                      int from, int to,
+                                      const FloatPoint&);
+    ~TransparencyAwareUniscribePainter();
+
+    // Uniscibe will draw directly into our buffer, so we need to expose our DC.
+    HDC hdc() const { return m_hdc; }
+
+ private:
+    virtual IntRect estimateTextBounds();
+
+    const Font* m_font;
+    const TextRun& m_run;
+    int m_from;
+    int m_to;
+};
+
+TransparencyAwareUniscribePainter::TransparencyAwareUniscribePainter(
+    GraphicsContext* context,
+    const Font* font,
+    const TextRun& run,
+    int from, int to,
+    const FloatPoint& point)
+    : TransparencyAwareFontPainter(context, point)
+    , m_font(font)
+    , m_run(run)
+    , m_from(from)
+    , m_to(to)
+{
+    init();
+}
+
+TransparencyAwareUniscribePainter::~TransparencyAwareUniscribePainter()
+{
+}
+
+IntRect TransparencyAwareUniscribePainter::estimateTextBounds()
+{
+    // This case really really sucks. There is no convenient way to estimate
+    // the bounding box. So we run Uniscribe twice. If we find this happens a
+    // lot, the way to fix it is to make the extra layer after the
+    // UniscribeHelper has measured the text.
+    IntPoint intPoint(lroundf(m_point.x()),
+                      lroundf(m_point.y()));
+
+    UniscribeHelperTextRun state(m_run, *m_font);
+    int left = lroundf(m_point.x()) + state.characterToX(m_from);
+    int right = lroundf(m_point.x()) + state.characterToX(m_to);
+    
+    // Adjust for RTL script since we just want to know the text bounds.
+    if (left > right)
+        std::swap(left, right);
+
+    // This algorithm for estimating how much extra space we need (the text may
+    // go outside the selection rect) is based roughly on
+    // TransparencyAwareGlyphPainter::estimateTextBounds above.
+    const FontMetrics& fontMetrics = m_font->fontMetrics();
+    return IntRect(left - (fontMetrics.ascent() + fontMetrics.descent()) / 2,
+                   m_point.y() - fontMetrics.ascent() - fontMetrics.lineGap(),
+                   (right - left) + fontMetrics.ascent() + fontMetrics.descent(),
+                   fontMetrics.lineSpacing());
+}
+
+} // namespace
+#endif
+
 bool Font::canReturnFallbackFontsForComplexText()
 {
     return false;
@@ -55,6 +380,7 @@
     return false;
 }
 
+#if ENABLE(SKIA_TEXT)
 void Font::drawGlyphs(GraphicsContext* graphicsContext,
                       const SimpleFontData* font,
                       const GlyphBuffer& glyphBuffer,
@@ -113,7 +439,107 @@
         paintSkiaText(graphicsContext, hfont, curLen, &glyphs[0], &advances[0], 0, &origin);
     }
 }
+#else
+static void drawGlyphsWin(GraphicsContext* graphicsContext,
+                          const SimpleFontData* font,
+                          const GlyphBuffer& glyphBuffer,
+                          int from,
+                          int numGlyphs,
+                          const FloatPoint& point) {
+    TransparencyAwareGlyphPainter painter(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
 
+    // We draw the glyphs in chunks to avoid having to do a heap allocation for
+    // the arrays of characters and advances. Since ExtTextOut is the
+    // lowest-level text output function on Windows, there should be little
+    // penalty for splitting up the text. On the other hand, the buffer cannot
+    // be bigger than 4094 or the function will fail.
+    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 = 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;
+        }
+
+        // Actually draw the glyphs (with retry on failure).
+        bool success = false;
+        for (int executions = 0; executions < 2; ++executions) {
+            success = painter.drawGlyphs(curLen, &glyphs[0], &advances[0], horizontalOffset - point.x() - currentWidth);
+            if (!success && !executions) {
+                // Ask the browser to load the font for us and retry.
+                PlatformSupport::ensureFontLoaded(font->platformData().hfont());
+                continue;
+            }
+            break;
+        }
+
+        if (!success)
+            LOG_ERROR("Unable to draw the glyphs after second attempt");
+    }
+}
+
+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;
+    if (!alpha || windowsCanHandleDrawTextShadow(graphicsContext) || !windowsCanHandleTextDrawingWithoutShadow(graphicsContext)) {
+        drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+        return;
+    }
+    // Draw in two passes: skia for the shadow, GDI for foreground text
+    // pass1: shadow (will use skia)
+    graphicsContext->save();
+    graphicsContext->setFillColor(Color::transparent, graphicsContext->fillColorSpace());
+    drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+    graphicsContext->restore();
+    // pass2: foreground text (will use GDI)
+    FloatSize shadowOffset;
+    float shadowBlur;
+    Color shadowColor;
+    ColorSpace shadowColorSpace;
+    graphicsContext->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+    graphicsContext->setShadow(shadowOffset, shadowBlur, Color::transparent, shadowColorSpace);
+    drawGlyphsWin(graphicsContext, font, glyphBuffer, from, numGlyphs, point);
+    graphicsContext->setShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+}
+#endif
+
 FloatRect Font::selectionRectForComplexText(const TextRun& run,
                                             const FloatPoint& point,
                                             int h,
@@ -148,9 +574,40 @@
     if (!alpha && graphicsContext->platformContext()->getStrokeStyle() == NoStroke)
         return;
 
+#if ENABLE(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.
-    HDC hdc = 0;
     state.draw(graphicsContext, hdc, lroundf(point.x()), lroundf(point.y() - fontMetrics().ascent()), from, to);
 }
 

Modified: trunk/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/chromium/UniscribeHelper.cpp	2011-10-11 13:11:33 UTC (rev 97149)
@@ -318,6 +318,9 @@
     HGDIOBJ oldFont = 0;
     int curX = x;
     bool firstRun = true;
+#if !ENABLE(SKIA_TEXT)
+    bool useWindowsDrawing = windowsCanHandleTextDrawing(graphicsContext);
+#endif
 
     for (size_t screenIndex = 0; screenIndex < m_runs.size(); screenIndex++) {
         int itemIndex = m_screenOrder[screenIndex];
@@ -396,14 +399,26 @@
             // Pass 0 in when there is no justification.
             const int* justify = shaping.m_justify.size() == 0 ? 0 : &shaping.m_justify[fromGlyph];
 
+#if ENABLE(SKIA_TEXT)
             const int* advances = shaping.m_justify.size() ?
                                       &shaping.m_justify[fromGlyph]
                                     : &shaping.m_advance[fromGlyph];
+#else
+            if (useWindowsDrawing) {
+                if (firstRun) {
+                    oldFont = SelectObject(dc, shaping.m_hfont);
+                    firstRun = false;
+                } else
+                    SelectObject(dc, shaping.m_hfont);
+            }
+
+#endif
             // 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 ENABLE(SKIA_TEXT)
                 SkPoint origin;
                 origin.fX = curX + + innerOffset;
                 origin.fY = y + m_ascent;
@@ -415,6 +430,32 @@
                               &shaping.m_offsets[fromGlyph],
                               &origin);
                 textOutOk = true;
+#else
+                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]);
+                    textOutOk = (hr == S_OK);
+                } else {
+                    SkPoint origin;
+                    origin.fX = curX + + innerOffset;
+                    origin.fY = y + m_ascent;
+                    paintSkiaText(graphicsContext,
+                                  shaping.m_hfont,
+                                  glyphCount,
+                                  &shaping.m_glyphs[fromGlyph],
+                                  &shaping.m_advance[fromGlyph],
+                                  &shaping.m_offsets[fromGlyph],
+                                  &origin);
+                    textOutOk = true;
+                }
+#endif
 
                 if (!textOutOk && 0 == executions) {
                     // If TextOut is called from the renderer it might fail

Modified: trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp	2011-10-11 13:11:33 UTC (rev 97149)
@@ -579,6 +579,17 @@
     return &m_canvas->getDevice()->accessBitmap(false);
 }
 
+bool PlatformContextSkia::isNativeFontRenderingAllowed()
+{
+#if ENABLE(SKIA_TEXT)
+    return false;
+#else
+    if (isAccelerated())
+        return false;
+    return skia::SupportsPlatformPaint(m_canvas);
+#endif
+}
+
 void PlatformContextSkia::getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const
 {
     *srcSize = m_imageResamplingHintSrcSize;

Modified: trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h	2011-10-11 13:11:33 UTC (rev 97149)
@@ -167,6 +167,12 @@
     bool printing() const { return m_printing; }
     void setPrinting(bool p) { m_printing = p; }
 
+    // Returns if the context allows rendering of fonts using native platform
+    // APIs. If false is returned font rendering is performed using the skia
+    // text drawing APIs.
+    // if SKIA_TEXT is enabled, this always returns false
+    bool isNativeFontRenderingAllowed();
+
     void getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const;
     void setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize);
     void clearImageResamplingHint();

Modified: trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.cpp	2011-10-11 13:11:33 UTC (rev 97149)
@@ -43,6 +43,60 @@
 
 namespace WebCore {
 
+#if !ENABLE(SKIA_TEXT)
+bool windowsCanHandleDrawTextShadow(GraphicsContext* context)
+{
+    FloatSize shadowOffset;
+    float shadowBlur;
+    Color shadowColor;
+    ColorSpace shadowColorSpace;
+
+    bool hasShadow = context->getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
+    return !hasShadow || (!shadowBlur && (shadowColor.alpha() == 255) && (context->fillColor().alpha() == 255));
+}
+
+bool windowsCanHandleTextDrawing(GraphicsContext* context)
+{
+    if (!windowsCanHandleTextDrawingWithoutShadow(context))
+        return false;
+
+    // Check for shadow effects.
+    if (!windowsCanHandleDrawTextShadow(context))
+        return false;
+
+    return true;
+}
+
+bool windowsCanHandleTextDrawingWithoutShadow(GraphicsContext* context)
+{
+    // Check for non-translation transforms. Sometimes zooms will look better in
+    // Skia, and sometimes better in Windows. The main problem is that zooming
+    // in using Skia will show you the hinted outlines for the smaller size,
+    // which look weird. All else being equal, it's better to use Windows' text
+    // drawing, so we don't check for zooms.
+    const AffineTransform& matrix = context->getCTM();
+    if (matrix.b() || matrix.c()) // Check for skew.
+        return false;
+
+    // Check for stroke effects.
+    if (context->platformContext()->getTextDrawingMode() != TextModeFill)
+        return false;
+
+    // Check for gradients.
+    if (context->fillGradient() || context->strokeGradient())
+        return false;
+
+    // Check for patterns.
+    if (context->fillPattern() || context->strokePattern())
+        return false;
+
+    if (!context->platformContext()->isNativeFontRenderingAllowed())
+        return false;
+
+    return true;
+}
+#endif
+
 static void skiaDrawText(SkCanvas* canvas,
                          const SkPoint& point,
                          SkPaint* paint,

Modified: trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.h (97148 => 97149)


--- trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.h	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebCore/platform/graphics/skia/SkiaFontWin.h	2011-10-11 13:11:33 UTC (rev 97149)
@@ -34,12 +34,41 @@
 #include <windows.h>
 #include <usp10.h>
 
-class SkPoint;
+struct SkPoint;
 
 namespace WebCore {
 
 class GraphicsContext;
+class PlatformContextSkia;
 
+#if !ENABLE(SKIA_TEXT)
+// The functions below are used for more complex font drawing (effects such as
+// stroking and more complex transforms) than Windows supports directly. Since
+// Windows drawing is faster you should use windowsCanHandleTextDrawing first to
+// check if using Skia is required at all.
+// Note that the text will look different (no ClearType) so this should only be
+// used when necessary.
+//
+// When you call a Skia* text drawing function, various glyph outlines will be
+// cached. As a result, you should call SkiaWinOutlineCache::removePathsForFont
+// when the font is destroyed so that the cache does not outlive the font (since
+// the HFONTs are recycled).
+//
+// Remember that Skia's text drawing origin is the baseline, like WebKit, not
+// the top, like Windows.
+
+// Returns true if the fillColor and shadowColor are opaque and the text-shadow
+// is not blurred.
+bool windowsCanHandleDrawTextShadow(GraphicsContext*);
+
+// Returns true if advanced font rendering is recommended.
+bool windowsCanHandleTextDrawing(GraphicsContext*);
+
+// Returns true if advanced font rendering is recommended if shadows are
+// disregarded.
+bool windowsCanHandleTextDrawingWithoutShadow(GraphicsContext*);
+#endif
+
 // Note that the offsets parameter is optional.  If not NULL it represents a
 // per glyph offset (such as returned by ScriptPlace Windows API function).
 void paintSkiaText(GraphicsContext*,

Modified: trunk/Source/WebKit/chromium/ChangeLog (97148 => 97149)


--- trunk/Source/WebKit/chromium/ChangeLog	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebKit/chromium/ChangeLog	2011-10-11 13:11:33 UTC (rev 97149)
@@ -1,3 +1,12 @@
+2011-10-11  Mike Reed  <r...@google.com>
+
+        re-add support for GDI text behind a compile flag
+        https://bugs.webkit.org/show_bug.cgi?id=69530
+
+        Reviewed by James Robinson.
+
+        * features.gypi:
+
 2011-10-11  Pavel Podivilov  <podivi...@chromium.org>
 
         Unreviewed, roll chromium revision to pick HTML speech input images update.

Modified: trunk/Source/WebKit/chromium/features.gypi (97148 => 97149)


--- trunk/Source/WebKit/chromium/features.gypi	2011-10-11 12:54:19 UTC (rev 97148)
+++ trunk/Source/WebKit/chromium/features.gypi	2011-10-11 13:11:33 UTC (rev 97149)
@@ -79,6 +79,7 @@
       'ENABLE_SANDBOX=1',
       'ENABLE_SHARED_WORKERS=1',
       'ENABLE_SKIA_GPU=<(use_skia_gpu)',
+      'ENABLE_SKIA_TEXT=<(enable_skia_text)',
       'ENABLE_SMOOTH_SCROLLING=1',
       'ENABLE_SQL_DATABASE=1',
       'ENABLE_SVG=<(enable_svg)',
@@ -109,6 +110,7 @@
     'variables': {
       'use_accelerated_compositing%': 1,
       'use_threaded_compositing%': 0,
+      'enable_skia_text%': 0,
       'enable_svg%': 1,
       'enable_touch_events%': 1,
       'use_skia_gpu%': 0,
@@ -118,6 +120,7 @@
     },
     'use_accelerated_compositing%': '<(use_accelerated_compositing)',
     'use_threaded_compositing%': '<(use_threaded_compositing)',
+    'enable_skia_text%': '<(enable_skia_text)',
     'enable_svg%': '<(enable_svg)',
     'enable_touch_events%': '<(enable_touch_events)',
     'use_skia%': '<(use_skia)',
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to