Add support for GDI text on Windows.
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 19:24:10 +0000 (19:24 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 19 Dec 2007 19:24:10 +0000 (19:24 +0000)
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@28867 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
WebCore/ChangeLog
WebCore/css/CSSStyleSelector.cpp
WebCore/dom/Document.cpp
WebCore/page/Settings.cpp
WebCore/page/Settings.h
WebCore/platform/graphics/Font.h
WebCore/platform/graphics/FontCache.cpp
WebCore/platform/graphics/FontDescription.h
WebCore/platform/graphics/GraphicsContext.h
WebCore/platform/graphics/win/FontCacheWin.cpp
WebCore/platform/graphics/win/FontDataWin.cpp
WebCore/platform/graphics/win/FontPlatformData.h
WebCore/platform/graphics/win/FontPlatformDataWin.cpp
WebCore/platform/graphics/win/FontWin.cpp
WebCore/platform/graphics/win/IconWin.cpp
WebCore/platform/win/GraphicsContextWin.cpp
WebCore/platform/win/UniscribeController.cpp
WebCore/platform/win/UniscribeController.h
WebCore/plugins/win/PluginViewWin.cpp

index 6a90cd5..5f96762 100644 (file)
@@ -1,3 +1,59 @@
+2007-12-19  Dave Hyatt  <hyatt@apple.com>
+
+        Add support for GDI text rendering to WebKit.
+      
+        Reviewed by mitz
+        
+        * css/CSSStyleSelector.cpp:
+        (WebCore::CSSStyleSelector::applyProperty):
+        * dom/Document.cpp:
+        (WebCore::Document::recalcStyle):
+        * page/Settings.cpp:
+        (WebCore::Settings::setFontRenderingMode):
+        (WebCore::Settings::fontRenderingMode):
+        * page/Settings.h:
+        * platform/graphics/Font.h:
+        (WebCore::Font::renderingMode):
+        * platform/graphics/FontCache.cpp:
+        (WebCore::FontPlatformDataCacheKey::FontPlatformDataCacheKey):
+        (WebCore::FontPlatformDataCacheKey::operator==):
+        (WebCore::computeHash):
+        (WebCore::FontCache::getCachedFontPlatformData):
+        * platform/graphics/FontDescription.h:
+        (WebCore::):
+        (WebCore::FontDescription::FontDescription):
+        (WebCore::FontDescription::renderingMode):
+        (WebCore::FontDescription::setRenderingMode):
+        (WebCore::FontDescription::operator==):
+        * platform/graphics/GraphicsContext.h:
+        * platform/graphics/win/FontCacheWin.cpp:
+        (WebCore::FontCache::fontExists):
+        (WebCore::FontCache::createFontPlatformData):
+        * platform/graphics/win/FontDataWin.cpp:
+        (WebCore::FontData::platformInit):
+        (WebCore::FontData::smallCapsFontData):
+        (WebCore::FontData::containsCharacters):
+        (WebCore::FontData::determinePitch):
+        (WebCore::FontData::platformWidthForGlyph):
+        * platform/graphics/win/FontPlatformData.h:
+        (WebCore::FontPlatformData::FontPlatformData):
+        (WebCore::FontPlatformData::useGDI):
+        (WebCore::FontPlatformData::operator==):
+        * platform/graphics/win/FontPlatformDataWin.cpp:
+        (WebCore::FontPlatformData::FontPlatformData):
+        * platform/graphics/win/FontWin.cpp:
+        (WebCore::Font::drawGlyphs):
+        * platform/graphics/win/IconWin.cpp:
+        (WebCore::Icon::paint):
+        * platform/win/GraphicsContextWin.cpp:
+        (WebCore::GraphicsContext::getWindowsContext):
+        (WebCore::GraphicsContext::releaseWindowsContext):
+        * platform/win/UniscribeController.cpp:
+        (WebCore::UniscribeController::shapeAndPlaceItem):
+        * platform/win/UniscribeController.h:
+        * plugins/win/PluginViewWin.cpp:
+        (WebCore::PluginViewWin::paint):
+
 2007-12-19  Sven Herzberg  <sven@imendio.com>
 
         Reviewed by Alp Toker.
index 1e8ec54..50778d3 100644 (file)
@@ -3338,8 +3338,11 @@ void CSSStyleSelector::applyProperty(int id, CSSValue *value)
             if (style->setFontDescription(fontDescription))
                 fontDirty = true;
         } else if (isInitial) {
+            Settings* settings = m_document->settings();
             FontDescription fontDescription;
             fontDescription.setGenericFamily(FontDescription::StandardFamily);
+            fontDescription.setRenderingMode(settings->fontRenderingMode());
+            fontDescription.setUsePrinterFont(m_document->printing());
             const AtomicString& standardFontFamily = m_document->settings()->standardFontFamily();
             if (!standardFontFamily.isEmpty()) {
                 fontDescription.firstFamily().setFamily(standardFontFamily);
index d31ef1c..825a339 100644 (file)
@@ -1064,6 +1064,7 @@ void Document::recalcStyle(StyleChange change)
         FontDescription fontDescription;
         fontDescription.setUsePrinterFont(printing());
         if (Settings* settings = this->settings()) {
+            fontDescription.setRenderingMode(settings->fontRenderingMode());
             if (printing() && !settings->shouldPrintBackgrounds())
                 _style->setForceBackgroundsToWhite(true);
             const AtomicString& stdfont = settings->standardFontFamily();
index ee84b60..f1097e6 100644 (file)
@@ -314,4 +314,17 @@ unsigned long long Settings::defaultDatabaseOriginQuota() const
 #endif
 }
 
+void Settings::setFontRenderingMode(FontRenderingMode mode)
+{
+    if (m_fontRenderingMode == mode)
+        return;
+    m_fontRenderingMode = mode;
+    setNeedsReapplyStylesInAllFrames(m_page);
+}
+
+FontRenderingMode Settings::fontRenderingMode() const
+{
+    return m_fontRenderingMode;
+}
+
 } // namespace WebCore
index 6029a09..58fffbf 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "AtomicString.h"
 #include "KURL.h"
+#include "FontDescription.h"
 
 namespace WebCore {
 
@@ -146,6 +147,9 @@ namespace WebCore {
         void setDefaultDatabaseOriginQuota(unsigned long long);
         unsigned long long defaultDatabaseOriginQuota() const;
         
+        void setFontRenderingMode(FontRenderingMode mode);
+        FontRenderingMode fontRenderingMode() const;
+
     private:
         Page* m_page;
         
@@ -181,6 +185,7 @@ namespace WebCore {
         bool m_forceFTPDirectoryListings : 1;
         bool m_developerExtrasEnabled : 1;
         bool m_authorAndUserStylesEnabled : 1;
+        FontRenderingMode m_fontRenderingMode : 1;
     };
 
 } // namespace WebCore
index eec378f..3c19fae 100644 (file)
@@ -159,6 +159,8 @@ public:
 
     bool isFixedPitch() const;
     bool isPrinterFont() const { return m_fontDescription.usePrinterFont(); }
+    
+    FontRenderingMode renderingMode() const { return m_fontDescription.renderingMode(); }
 
     FontFamily& firstFamily() { return m_fontDescription.firstFamily(); }
     const FontFamily& family() const { return m_fontDescription.family(); }
index 5a59e3a..d1aba16 100644 (file)
@@ -40,19 +40,21 @@ namespace WebCore {
 
 struct FontPlatformDataCacheKey {
     FontPlatformDataCacheKey(const AtomicString& family = AtomicString(), unsigned size = 0, bool bold = false, bool italic = false,
-                             bool isPrinterFont = false)
+                             bool isPrinterFont = false, FontRenderingMode renderingMode = NormalRenderingMode)
         : m_family(family)
         , m_size(size)
         , m_bold(bold)
         , m_italic(italic)
         , m_printerFont(isPrinterFont)
+        , m_renderingMode(renderingMode)
     {
     }
 
     bool operator==(const FontPlatformDataCacheKey& other) const
     {
         return equalIgnoringCase(m_family, other.m_family) && m_size == other.m_size && 
-               m_bold == other.m_bold && m_italic == other.m_italic && m_printerFont == other.m_printerFont;
+               m_bold == other.m_bold && m_italic == other.m_italic && m_printerFont == other.m_printerFont &&
+               m_renderingMode == other.m_renderingMode;
     }
     
     AtomicString m_family;
@@ -60,16 +62,18 @@ struct FontPlatformDataCacheKey {
     bool m_bold;
     bool m_italic;
     bool m_printerFont;
+    FontRenderingMode m_renderingMode;
 };
 
 inline unsigned computeHash(const FontPlatformDataCacheKey& fontKey)
 {
-    unsigned hashCodes[3] = {
+    unsigned hashCodes[4] = {
         CaseFoldingHash::hash(fontKey.m_family),
         fontKey.m_size,
-        static_cast<unsigned>(fontKey.m_bold) << 2 | static_cast<unsigned>(fontKey.m_italic) << 1 | static_cast<unsigned>(fontKey.m_printerFont)
+        static_cast<unsigned>(fontKey.m_bold) << 3 | static_cast<unsigned>(fontKey.m_italic) << 2 | static_cast<unsigned>(fontKey.m_printerFont) << 1 |
+        static_cast<unsigned>(fontKey.m_renderingMode)
     };
-    return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar));
+    return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 4 * sizeof(unsigned) / sizeof(UChar));
 }
 
 struct FontPlatformDataCacheKeyHash {
@@ -141,7 +145,7 @@ FontPlatformData* FontCache::getCachedFontPlatformData(const FontDescription& fo
     }
 
     FontPlatformDataCacheKey key(familyName, fontDescription.computedPixelSize(), fontDescription.bold(), fontDescription.italic(),
-                                 fontDescription.usePrinterFont());
+                                 fontDescription.usePrinterFont(), fontDescription.renderingMode());
     FontPlatformData* result = 0;
     bool foundResult;
     FontPlatformDataCache::iterator it = gFontPlatformDataCache->find(key);
index 828fc73..6bb232e 100644 (file)
@@ -31,6 +31,10 @@ namespace WebCore {
 const unsigned cNormalWeight = 50;
 const unsigned cBoldWeight = 63;
 
+// This setting is used to provide ways of switching between multiple rendering modes that may have different
+// metrics.  It is used to switch between CG and GDI text on Windows.
+enum FontRenderingMode { NormalRenderingMode, AlternateRenderingMode };
+
 class FontDescription {
 public:
     enum GenericFamilyType { NoFamily, StandardFamily, SerifFamily, SansSerifFamily, 
@@ -39,7 +43,7 @@ public:
     FontDescription()
         : m_specifiedSize(0), m_computedSize(0), 
           m_italic(false), m_smallCaps(false), m_isAbsoluteSize(false), m_weight(cNormalWeight), 
-          m_genericFamily(NoFamily), m_usePrinterFont(false), m_keywordSize(0)
+          m_genericFamily(NoFamily), m_usePrinterFont(false), m_renderingMode(NormalRenderingMode), m_keywordSize(0)
           {}
     
     bool operator==(const FontDescription&) const;
@@ -57,6 +61,7 @@ public:
     unsigned weight() const { return m_weight; }
     GenericFamilyType genericFamily() const { return static_cast<GenericFamilyType>(m_genericFamily); }
     bool usePrinterFont() const { return m_usePrinterFont; }
+    FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); }
     int keywordSize() const { return m_keywordSize; }
 
     void setFamily(const FontFamily& family) { m_familyList = family; }
@@ -69,6 +74,7 @@ public:
     void setWeight(unsigned w) { m_weight = w; }
     void setGenericFamily(GenericFamilyType genericFamily) { m_genericFamily = genericFamily; }
     void setUsePrinterFont(bool p) { m_usePrinterFont = p; }
+    void setRenderingMode(FontRenderingMode mode) { m_renderingMode = mode; }
     void setKeywordSize(int s) { m_keywordSize = s; }
 
 private:
@@ -85,7 +91,9 @@ private:
     unsigned m_weight : 8;
     unsigned m_genericFamily : 3; // GenericFamilyType
     bool m_usePrinterFont : 1;
-    
+
+    unsigned m_renderingMode : 1;  // Used to switch between CG and GDI text on Windows.
+
     int m_keywordSize : 4; // We cache whether or not a font is currently represented by a CSS keyword (e.g., medium).  If so,
                            // then we can accurately translate across different generic families to adjust for different preference settings
                            // (e.g., 13px monospace vs. 16px everything else).  Sizes are 1-8 (like the HTML size values for <font>).
@@ -102,6 +110,7 @@ inline bool FontDescription::operator==(const FontDescription& other) const
         && m_weight == other.m_weight
         && m_genericFamily == other.m_genericFamily
         && m_usePrinterFont == other.m_usePrinterFont
+        && m_renderingMode == other.m_renderingMode
         && m_keywordSize == other.m_keywordSize;
 }
 
index bf217e0..06d63f6 100644 (file)
@@ -221,8 +221,8 @@ namespace WebCore {
 
 #if PLATFORM(WIN)
         GraphicsContext(HDC); // FIXME: To be removed.
-        HDC getWindowsContext(bool supportAlphaBlend = false, const IntRect* = 0); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
-        void releaseWindowsContext(HDC, bool supportAlphaBlend = false, const IntRect* = 0);    // The passed in HDC should be the one handed back by getWindowsContext.
+        HDC getWindowsContext(const IntRect&, bool supportAlphaBlend = true); // The passed in rect is used to create a bitmap for compositing inside transparency layers.
+        void releaseWindowsContext(HDC, const IntRect&, bool supportAlphaBlend = true);    // The passed in HDC should be the one handed back by getWindowsContext.
 #endif
 
 #if PLATFORM(QT)
index 71675f7..046d2d3 100644 (file)
@@ -215,7 +215,7 @@ bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicS
     HFONT hfont = CreateFontIndirect(&winfont);
     // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
     // and see if the family name was really used.
-    HDC dc = GetDC((HWND)0);
+    HDC dc = GetDC(0);
     SaveDC(dc);
     SelectObject(dc, hfont);
     WCHAR name[LF_FACESIZE];
@@ -230,22 +230,28 @@ bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicS
 
 FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
 {
+    bool isLucidaGrande = false;
+    static AtomicString lucidaStr("Lucida Grande");
+    if (equalIgnoringCase(family, lucidaStr))
+        isLucidaGrande = true;
+
+    bool useGDI = fontDescription.renderingMode() == AlternateRenderingMode && !isLucidaGrande;
+
     LOGFONT winfont;
 
-    // The size here looks unusual.  The negative number is intentional.  The logical size constant is 32.
-    winfont.lfHeight = -fontDescription.computedPixelSize() * 32;
+    // The size here looks unusual.  The negative number is intentional.  The logical size constant is 32. We do this
+    // for subpixel precision when rendering using Uniscribe.  This masks rounding errors related to the HFONT metrics being
+    // different from the CGFont metrics.
+    // FIXME: We will eventually want subpixel precision for GDI mode, but the scaled rendering doesn't look as nice.  That may be solvable though.
+    winfont.lfHeight = -fontDescription.computedPixelSize() * (useGDI ? 1 : 32);
     winfont.lfWidth = 0;
     winfont.lfEscapement = 0;
     winfont.lfOrientation = 0;
     winfont.lfUnderline = false;
     winfont.lfStrikeOut = false;
     winfont.lfCharSet = DEFAULT_CHARSET;
-#if PLATFORM(CG)
     winfont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
-#else
-    winfont.lfOutPrecision = OUT_TT_PRECIS;
-#endif
-    winfont.lfQuality = 5; // Force cleartype.
+    winfont.lfQuality = DEFAULT_QUALITY;
     winfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
     winfont.lfItalic = fontDescription.italic();
 
@@ -254,10 +260,10 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
     // gaps in the weight list.
     // FIXME: Hardcoding Lucida Grande for now.  It uses different weights than typical Win32 fonts
     // (500/600 instead of 400/700).
-    static AtomicString lucidaStr("Lucida Grande");
-    if (equalIgnoringCase(family, lucidaStr))
+    if (isLucidaGrande) {
         winfont.lfWeight = fontDescription.bold() ? 600 : 500;
-    else
+        useGDI = false; // Never use GDI for Lucida Grande.
+    } else
         winfont.lfWeight = fontDescription.bold() ? 700 : 400;
     int len = min(family.length(), (unsigned int)LF_FACESIZE - 1);
     memcpy(winfont.lfFaceName, family.characters(), len * sizeof(WORD));
@@ -266,7 +272,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
     HFONT hfont = CreateFontIndirect(&winfont);
     // Windows will always give us a valid pointer here, even if the face name is non-existent.  We have to double-check
     // and see if the family name was really used.
-    HDC dc = GetDC((HWND)0);
+    HDC dc = GetDC(0);
     SaveDC(dc);
     SelectObject(dc, hfont);
     WCHAR name[LF_FACESIZE];
@@ -280,7 +286,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
     }
     
     FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
-                                                    fontDescription.bold(), fontDescription.italic());
+                                                    fontDescription.bold(), fontDescription.italic(), useGDI);
     if (!result->cgFont()) {
         // The creation of the CGFontRef failed for some reason.  We already asserted in debug builds, but to make
         // absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
index f23bc49..faf0fe0 100644 (file)
@@ -59,6 +59,35 @@ void FontData::setShouldApplyMacAscentHack(bool b)
 void FontData::platformInit()
 {    
     m_syntheticBoldOffset = m_font.syntheticBold() ? 1.0f : 0.f;
+    m_scriptCache = 0;
+    m_scriptFontProperties = 0;
+    m_isSystemFont = false;
+    
+    if (m_font.useGDI()) {
+        HDC hdc = GetDC(0);
+        HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+        OUTLINETEXTMETRIC metrics;
+        GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+        TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+        m_ascent = textMetrics.tmAscent;
+        m_descent = textMetrics.tmDescent;
+        m_lineGap = textMetrics.tmExternalLeading;
+        m_lineSpacing = m_ascent + m_descent + m_lineGap;
+        m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+
+        GLYPHMETRICS gm;
+        MAT2 mat = { 1, 0, 0, 1 };
+        DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+        if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+            m_xHeight = gm.gmptGlyphOrigin.y;
+
+        m_unitsPerEm = metrics.otmEMSquare;
+
+        SelectObject(hdc, oldFont);
+        ReleaseDC(0, hdc);
+
+        return;
+    }
 
     CGFontRef font = m_font.cgFont();
     int iAscent = CGFontGetAscent(font);
@@ -70,7 +99,6 @@ void FontData::platformInit()
     float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
     float fLineGap = scaleEmToUnits(iLineGap, m_unitsPerEm) * pointSize;
 
-    m_isSystemFont = false;
     if (!isCustomFont()) {
         HDC dc = GetDC(0);
         HGDIOBJ oldFont = SelectObject(dc, m_font.hfont());
@@ -115,9 +143,6 @@ void FontData::platformInit()
         int iXHeight = CGFontGetXHeight(font);
         m_xHeight = scaleEmToUnits(iXHeight, m_unitsPerEm) * pointSize;
     }
-
-    m_scriptCache = 0;
-    m_scriptFontProperties = 0;
 }
 
 void FontData::platformDestroy()
@@ -145,9 +170,9 @@ FontData* FontData::smallCapsFontData(const FontDescription& fontDescription) co
         } else {
             LOGFONT winfont;
             GetObject(m_font.hfont(), sizeof(LOGFONT), &winfont);
-            winfont.lfHeight = -lroundf(smallCapsHeight * 32);
+            winfont.lfHeight = -lroundf(smallCapsHeight * m_font.useGDI() ? 1 : 32);
             HFONT hfont = CreateFontIndirect(&winfont);
-            m_smallCapsFontData = new FontData(FontPlatformData(hfont, smallCapsHeight, fontDescription.bold(), fontDescription.italic()));
+            m_smallCapsFontData = new FontData(FontPlatformData(hfont, smallCapsHeight, fontDescription.bold(), fontDescription.italic(), m_font.useGDI()));
         }
     }
     return m_smallCapsFontData;
@@ -166,7 +191,7 @@ bool FontData::containsCharacters(const UChar* characters, int length) const
     if (!langFontLink)
         return false;
 
-    HDC dc = GetDC((HWND)0);
+    HDC dc = GetDC(0);
     
     DWORD acpCodePages;
     langFontLink->CodePageToCodePages(CP_ACP, &acpCodePages);
@@ -197,7 +222,7 @@ void FontData::determinePitch()
     }
 
     // TEXTMETRICS have this.  Set m_treatAsFixedPitch based off that.
-    HDC dc = GetDC((HWND)0);
+    HDC dc = GetDC(0);
     SaveDC(dc);
     SelectObject(dc, m_font.hfont());
 
@@ -213,6 +238,16 @@ void FontData::determinePitch()
 
 float FontData::platformWidthForGlyph(Glyph glyph) const
 {
+    if (m_font.useGDI()) {
+        HDC hdc = GetDC(0);
+        HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+        int width;
+        GetCharWidthI(hdc, glyph, 1, 0, &width);
+        SelectObject(hdc, oldFont);
+        ReleaseDC(0, hdc);
+        return width;
+    }
+
     CGFontRef font = m_font.cgFont();
     float pointSize = m_font.size();
     CGSize advance;
index a83b4be..1b448e1 100644 (file)
@@ -45,6 +45,7 @@ public:
     , m_size(0)
     , m_syntheticBold(false)
     , m_syntheticOblique(false)
+    , m_useGDI(false)
     {}
 
     FontPlatformData()
@@ -53,9 +54,10 @@ public:
     , m_size(0)
     , m_syntheticBold(false)
     , m_syntheticOblique(false)
+    , m_useGDI(false)
     {}
 
-    FontPlatformData(HFONT, float size, bool bold, bool oblique);
+    FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
     FontPlatformData(CGFontRef, float size, bool bold, bool oblique);
     ~FontPlatformData();
 
@@ -66,6 +68,7 @@ public:
     void setSize(float size) { m_size = size; }
     bool syntheticBold() const { return m_syntheticBold; }
     bool syntheticOblique() const { return m_syntheticOblique; }
+    bool useGDI() const { return m_useGDI; }
 
     unsigned hash() const
     {
@@ -75,7 +78,8 @@ public:
     bool operator==(const FontPlatformData& other) const
     { 
         return m_font == other.m_font && m_cgFont ==other.m_cgFont && m_size == other.m_size &&
-               m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique;
+               m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
+               m_useGDI == other.m_useGDI;
     }
 
 private:
@@ -85,6 +89,7 @@ private:
     float m_size;
     bool m_syntheticBold;
     bool m_syntheticOblique;
+    bool m_useGDI;
 };
 
 }
index b3210de..c944b6d 100644 (file)
@@ -128,12 +128,13 @@ static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC*
     return 1;
 }
 
-FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique)
+FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
     : m_font(font)
     , m_size(size)
     , m_cgFont(0)
     , m_syntheticBold(false)
     , m_syntheticOblique(false)
+    , m_useGDI(useGDI)
 {
     HDC hdc = GetDC(0);
     SaveDC(hdc);
@@ -178,6 +179,9 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
                     m_syntheticOblique = true;
         }
 
+        // For GDI text, synthetic bold and oblique never need to be set.
+        m_syntheticBold = m_syntheticOblique = false;
+
         // Try the face name first.  Windows may end up localizing this name, and CG doesn't know about
         // the localization.  If the create fails, we'll try the PostScript name.
         RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
@@ -202,6 +206,7 @@ FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool o
     , m_cgFont(font)
     , m_syntheticBold(bold)
     , m_syntheticOblique(oblique)
+    , m_useGDI(false)
 {
 }
 
index 231269c..d2ce873 100644 (file)
@@ -44,6 +44,88 @@ const int syntheticObliqueAngle = 14;
 void Font::drawGlyphs(GraphicsContext* graphicsContext, const FontData* font, const GlyphBuffer& glyphBuffer, 
                       int from, int numGlyphs, const FloatPoint& point) const
 {
+    if (font->m_font.useGDI()) {
+        // FIXME: Support alpha blending.
+        // FIXME: Support text stroke/fill.
+        // FIXME: Support text shadow.
+        Color fillColor = graphicsContext->fillColor();
+        if (fillColor.alpha() == 0)
+            return;
+
+        // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances.
+        Vector<int, 2048> gdiAdvances;
+        int totalWidth = 0;
+        for (int i = 0; i < numGlyphs; i++) {
+            gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i)));
+            totalWidth += gdiAdvances[i];
+        }
+
+        // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges.
+        IntRect textRect(point.x() - font->lineGap(), point.y() - font->ascent() - font->lineGap(), totalWidth + 2 * font->lineGap(), font->lineSpacing());
+        HDC hdc = graphicsContext->getWindowsContext(textRect);
+        SelectObject(hdc, font->m_font.hfont());
+
+        // Set the correct color.
+        HDC textDrawingDC = hdc;
+        /*if (fillColor.hasAlpha() || graphicsContext->inTransparencyLayer()) {
+            // GDI can't handle drawing transparent text.  We have to draw into a mask.  We draw black text on a white-filled background.
+            // We also do this when inside transparency layers, since GDI also can't draw onto a surface with alpha.
+            graphicsContext->save();
+            graphicsContext->setFillColor(Color::white);
+            textDrawingDC = graphicsContext->getWindowsBitmapContext(textRect);
+            SetTextColor(hdc, RGB(0, 0, 0));
+        } else*/
+            SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue()));
+
+        SetBkMode(hdc, TRANSPARENT);
+        SetTextAlign(hdc, TA_LEFT | TA_BASELINE);
+
+        // Uniscribe gives us offsets to help refine the positioning of combining glyphs.
+        FloatSize translation = glyphBuffer.offsetAt(from);
+        if (translation.width() || translation.height()) {
+            XFORM xform;
+            xform.eM11 = 1.0;
+            xform.eM12 = 0;
+            xform.eM21 = 0;
+            xform.eM22 = 1.0;
+            xform.eDx = translation.width();
+            xform.eDy = translation.height();
+            ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
+        }
+        ExtTextOut(hdc, point.x(), point.y(), ETO_GLYPH_INDEX, 0, (WCHAR*)glyphBuffer.glyphs(from), numGlyphs, gdiAdvances.data());
+
+        /*if (fillColor.hasAlpha() || graphicsContext->inTransparencyLayer()) {
+            // TODOD: We have to walk the bits of the bitmap and invert them.  We also copy over the green component value into the alpha value
+            // to keep ClearType looking reasonable.
+
+            // Now that we have drawn the text into a bitmap and inverted it, obtain a CGImageRef mask.
+            CGImageRef mask = graphicsContext->releaseWindowsBitmapContextIntoMask(textDrawingDC, textRect);
+            
+            // Apply the mask to the fill color.
+            CGContextRef bitmapContext = graphicsContext->getWindowsCompatibleCGBitmapContext(textRect.size());
+            CGFloat red, green, blue, alpha;
+            color.getRGBA(red, green, blue, alpha);
+            CGContextSetRGBFillColor(context, red, green, blue, alpha);
+            CGContextFillRect(bitmapContext, IntRect(0, 0, textRect.width(), textRect.height()));
+            CGImageRef fillColorImage = CGBitmapContextCreateImage(bitmapContext);
+        
+            // Apply the mask.
+            CGImageRef finalImage = CGImageCreateWithMask(fillColorImage, mask);
+
+            // The bitmap image needs to be drawn into the HDC.
+            graphicsContext->drawImageIntoWindowsContext(hdc, finalImage);
+
+            // Release our images and contexts.
+            CGImageRelease(mask);
+            CGImageRelease(fillColorImage);
+            CGImageRelease(finalImage);
+            CGContextRelease(bitmapContext);
+        }*/
+
+        graphicsContext->releaseWindowsContext(hdc, textRect);
+        return;
+    }
+
     CGContextRef cgContext = graphicsContext->platformContext();
 
     uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext);
index 2a902f7..60cebe3 100644 (file)
@@ -62,11 +62,11 @@ void Icon::paint(GraphicsContext* context, const IntRect& r)
     if (context->paintingDisabled())
         return;
 
-    HDC hdc = context->getWindowsContext();
+    HDC hdc = context->getWindowsContext(r);
 
     DrawIconEx(hdc, r.x(), r.y(), m_hIcon, r.width(), r.height(), 0, 0, DI_NORMAL);
 
-    context->releaseWindowsContext(hdc);
+    context->releaseWindowsContext(hdc, r);
 }
 
 }
index 076e18d..d77928d 100644 (file)
@@ -77,19 +77,17 @@ GraphicsContext::GraphicsContext(HDC hdc)
     }
 }
 
-HDC GraphicsContext::getWindowsContext(bool supportAlphaBlend, const IntRect* dstRect)
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend)
 {
     if (m_data->m_transparencyCount) {
-        // We're in a transparency layer.
-        ASSERT(dstRect);
-        if (!dstRect)
+        if (dstRect.isEmpty())
             return 0;
-    
+
         // Create a bitmap DC in which to draw.
         BITMAPINFO bitmapInfo;
         bitmapInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
-        bitmapInfo.bmiHeader.biWidth         = dstRect->width(); 
-        bitmapInfo.bmiHeader.biHeight        = dstRect->height();
+        bitmapInfo.bmiHeader.biWidth         = dstRect.width(); 
+        bitmapInfo.bmiHeader.biHeight        = dstRect.height();
         bitmapInfo.bmiHeader.biPlanes        = 1;
         bitmapInfo.bmiHeader.biBitCount      = 32;
         bitmapInfo.bmiHeader.biCompression   = BI_RGB;
@@ -124,8 +122,8 @@ HDC GraphicsContext::getWindowsContext(bool supportAlphaBlend, const IntRect* ds
         xform.eM12 = 0;
         xform.eM21 = 0;
         xform.eM22 = 1.0;
-        xform.eDx = -dstRect->x();
-        xform.eDy = -dstRect->y();
+        xform.eDx = -dstRect.x();
+        xform.eDy = -dstRect.y();
         ::SetWorldTransform(bitmapDC, &xform);
 
         return bitmapDC;
@@ -136,9 +134,12 @@ HDC GraphicsContext::getWindowsContext(bool supportAlphaBlend, const IntRect* ds
     return m_data->m_hdc;
 }
 
-void GraphicsContext::releaseWindowsContext(HDC hdc, bool supportAlphaBlend, const IntRect* dstRect)
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend)
 {
     if (hdc && m_data->m_transparencyCount) {
+        if (dstRect.isEmpty())
+            return;
+
         HBITMAP bitmap = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
 
         // Need to make a CGImage out of the bitmap's pixel buffer and then draw
@@ -154,7 +155,7 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, bool supportAlphaBlend, con
         CGColorSpaceRelease(deviceRGB);
 
         CGImageRef image = CGBitmapContextCreateImage(bitmapContext);
-        CGContextDrawImage(m_data->m_cgContext, *dstRect, image);
+        CGContextDrawImage(m_data->m_cgContext, dstRect, image);
         
         // Delete all our junk.
         CGImageRelease(image);
index 41c19eb..8773885 100644 (file)
@@ -253,7 +253,9 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const F
     roundingHackCharacters.fill(-1);
     Vector<int> roundingHackWordBoundaries(glyphs.size());
     roundingHackWordBoundaries.fill(-1);
-    unsigned logicalSpaceWidth = fontData->m_spaceWidth * 32.0f;
+
+    const float cLogicalScale = fontData->m_font.useGDI() ? 1.0f : 32.0f;
+    unsigned logicalSpaceWidth = fontData->m_spaceWidth * cLogicalScale;
     float roundedSpaceWidth = roundf(fontData->m_spaceWidth);
 
     for (int k = 0; k < len; k++) {
@@ -282,9 +284,9 @@ bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const F
 
     for (unsigned k = 0; k < glyphs.size(); k++) {
         Glyph glyph = glyphs[k];
-        float advance = advances[k] / 32.0f;
-        float offsetX = offsets[k].du / 32.0f;
-        float offsetY = offsets[k].dv / 32.0f;
+        float advance = advances[k] / cLogicalScale;
+        float offsetX = offsets[k].du / cLogicalScale;
+        float offsetY = offsets[k].dv / cLogicalScale;
 
         // Match AppKit's rules for the integer vs. non-integer rendering modes.
         float roundedAdvance = roundf(advance);
index 1fe0439..b96606a 100644 (file)
 #ifndef UniscribeController_h
 #define UniscribeController_h
 
+#include <usp10.h>
 #include "Font.h"
 #include "GlyphBuffer.h"
 #include "Vector.h"
-#include <usp10.h>
 
 namespace WebCore {
 
index ae2cb0c..8127228 100644 (file)
@@ -472,8 +472,10 @@ void PluginViewWin::paint(GraphicsContext* context, const IntRect& rect)
     if (m_isWindowed || context->paintingDisabled())
         return;
 
-    HDC hdc = context->getWindowsContext();
+    HDC hdc = context->getWindowsContext(frameGeometry());
 
+    // FIXME: This is completely wrong and will break in the presence of opacity, SVG transforms
+    // and CSS transforms.
     // The plugin expects that the passed in DC has window coordinates.
     // (This probably breaks funky SVG transform stuff)
     XFORM transform;
@@ -515,7 +517,7 @@ void PluginViewWin::paint(GraphicsContext* context, const IntRect& rect)
 
     dispatchNPEvent(npEvent);
 
-    context->releaseWindowsContext(hdc);
+    context->releaseWindowsContext(hdc, frameGeometry());
 }
 
 void PluginViewWin::handleKeyboardEvent(KeyboardEvent* event)