bug 502906 - part 4 - refactor DWrite font code to match Mac and GDI structure. r=bas
authorJonathan Kew <jfkthame@gmail.com>
Tue, 06 Apr 2010 21:19:39 +0100
changeset 40504 1cac391aec8cb87c8603052cd32e8594d733e8cd
parent 40503 260d768e55f4d471f0abbc00bca5968f590f1a31
child 40505 4365eabf7fb0737b3055ae5f5e9da8a0cd0032c2
push idunknown
push userunknown
push dateunknown
reviewersbas
bugs502906
milestone1.9.3a4pre
bug 502906 - part 4 - refactor DWrite font code to match Mac and GDI structure. r=bas
gfx/thebes/public/gfxDWriteFonts.h
gfx/thebes/src/Makefile.in
gfx/thebes/src/gfxDWriteFonts.cpp
gfx/thebes/src/gfxDWriteShaper.cpp
gfx/thebes/src/gfxDWriteShaper.h
gfx/thebes/src/gfxWindowsPlatform.cpp
--- a/gfx/thebes/public/gfxDWriteFonts.h
+++ b/gfx/thebes/public/gfxDWriteFonts.h
@@ -62,55 +62,27 @@ public:
     virtual PRUint32 GetSpaceGlyph();
 
     virtual PRBool SetupCairoFont(gfxContext *aContext);
 
     virtual PRBool IsValid() { return mFontFace != NULL; }
 
     gfxFloat GetAdjustedSize() const { return mAdjustedSize; }
 
+    IDWriteFontFace *GetFontFace() { return mFontFace.get(); }
+
 protected:
-    friend class gfxDWriteFontGroup;
-
     void ComputeMetrics();
 
     cairo_font_face_t *CairoFontFace();
 
     cairo_scaled_font_t *CairoScaledFont();
 
     nsRefPtr<IDWriteFontFace> mFontFace;
     cairo_font_face_t *mCairoFontFace;
     cairo_scaled_font_t *mCairoScaledFont;
 
     gfxFloat mAdjustedSize;
     gfxFont::Metrics mMetrics;
     PRBool mNeedsOblique;
 };
 
-/**
- * \brief Class representing a DWrite windows font group.
- */
-class gfxDWriteFontGroup : public gfxFontGroup 
-{
-public:
-    gfxDWriteFontGroup(const nsAString& aFamilies, 
-                              const gfxFontStyle *aStyle,
-                              gfxUserFontSet *aUserFontSet);
-    virtual ~gfxDWriteFontGroup();
-    
-    gfxFontGroup *Copy(const gfxFontStyle *aStyle);
-
-    /**
-     * Gets the font at a certain position in the font list, it will
-     * create this font if it hasn't actually been created yet.
-     *
-     * \param i Position in the font list
-     * \return Object representing the font
-     */
-    virtual gfxDWriteFont *GetFontAt(PRInt32 i);
-
-    virtual gfxTextRun *MakeTextRun(const PRUnichar *aString, PRUint32 aLength,
-                                    const Parameters *aParams, PRUint32 aFlags);
-    virtual gfxTextRun *MakeTextRun(const PRUint8 *aString, PRUint32 aLength,
-                                    const Parameters *aParams, PRUint32 aFlags);
-};
-
 #endif
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -66,16 +66,17 @@ CPPSRCS	+= gfxFT2Fonts.cpp \
 	   $(NULL)
 
 EXTRA_DSO_LDOPTS += $(FT2_LIBS)
 
 OS_LIBS += $(call EXPAND_LIBNAME,ddraw)
 else
 ifdef MOZ_ENABLE_DWRITE_FONT
 CPPSRCS	+= gfxDWriteFonts.cpp \
+	   gfxDWriteShaper.cpp \
 	   gfxDWriteTextAnalysis.cpp \
 	   gfxDWriteCommon.cpp \
 	   gfxD2DSurface.cpp \
 	   gfxDWriteFontList.cpp \
 	   $(NULL)
 endif
 CPPSRCS	+= gfxGDIFont.cpp \
 	   gfxGDIFontList.cpp \
--- a/gfx/thebes/src/gfxDWriteFonts.cpp
+++ b/gfx/thebes/src/gfxDWriteFonts.cpp
@@ -31,16 +31,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxDWriteFonts.h"
+#include "gfxDWriteShaper.h"
 #include "gfxDWriteFontList.h"
 #include "gfxContext.h"
 #include <dwrite.h>
 
 #include "gfxDWriteTextAnalysis.h"
 
 // Chosen this as to resemble DWrite's own oblique face style.
 #define OBLIQUE_SKEW_FACTOR 0.3
@@ -75,16 +76,18 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntr
     rv = fe->CreateFontFace(getter_AddRefs(mFontFace), sims);
 
     if (NS_FAILED(rv)) {
         mIsValid = PR_FALSE;
         return;
     }
 
     ComputeMetrics();
+
+    mShaper = new gfxDWriteShaper(this);
 }
 
 gfxDWriteFont::~gfxDWriteFont()
 {
     if (mCairoFontFace) {
         cairo_font_face_destroy(mCairoFontFace);
     }
     if (mCairoScaledFont) {
@@ -273,283 +276,8 @@ gfxDWriteFont::CairoScaledFont()
 
     NS_ASSERTION(mAdjustedSize == 0.0 ||
                  cairo_scaled_font_status(mCairoScaledFont) 
                    == CAIRO_STATUS_SUCCESS,
                  "Failed to make scaled font");
 
     return mCairoScaledFont;
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// gfxDWriteFontGroup
-gfxDWriteFontGroup::gfxDWriteFontGroup(const nsAString& aFamilies,
-                                       const gfxFontStyle *aStyle,
-                                       gfxUserFontSet *aUserFontSet)
-    : gfxFontGroup(aFamilies, aStyle, aUserFontSet)
-{
-}
-
-gfxDWriteFontGroup::~gfxDWriteFontGroup()
-{
-}
-
-gfxDWriteFont *
-gfxDWriteFontGroup::GetFontAt(PRInt32 i) 
-{
-    // If it turns out to be hard for all clients that cache font
-    // groups to call UpdateFontList at appropriate times, we could
-    // instead consider just calling UpdateFontList from someplace
-    // more central (such as here).
-    NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(),
-                 "Whoever was caching this font group should have "
-                 "called UpdateFontList on it");
-    NS_ASSERTION(mFonts.Length() > PRUint32(i), 
-                 "Requesting a font index that doesn't exist");
-
-    return static_cast<gfxDWriteFont*>(mFonts[i].get());
-}
-
-gfxFontGroup *
-gfxDWriteFontGroup::Copy(const gfxFontStyle *aStyle)
-{
-    return new gfxDWriteFontGroup(mFamilies, aStyle, mUserFontSet);
-}
-
-#define MAX_RANGE_LENGTH 25000
-gfxTextRun *
-gfxDWriteFontGroup::MakeTextRun(const PRUnichar *aString,
-                                PRUint32 aLength,
-                                const Parameters *aParams,
-                                PRUint32 aFlags)
-{
-    HRESULT hr;
-    // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
-
-    gfxTextRun *textRun = gfxTextRun::Create(aParams,
-                                             aString,
-                                             aLength,
-                                             this,
-                                             aFlags);
-
-    gfxPlatform::GetPlatform()->SetupClusterBoundaries(textRun, aString);
-
-    DWRITE_READING_DIRECTION readingDirection = 
-        DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
-    if (textRun->IsRightToLeft()) {
-        readingDirection = DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
-    }
-    nsRefPtr<gfxDWriteFont> font = GetFontAt(0);
-
-    textRun->AddGlyphRun(font, 0);
-    gfxTextRun::CompressedGlyph g;
-
-    nsRefPtr<IDWriteTextAnalyzer> analyzer;
-
-    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
-        CreateTextAnalyzer(getter_AddRefs(analyzer));
-
-    nsTArray<gfxTextRange> ranges;
-
-    ComputeRanges(ranges, aString, 0, aLength);
-
-    /**
-     * There's an internal 16-bit limit on some things inside the analyzer.
-     * to be on the safe side here we split up any ranges over MAX_RANGE_LENGTH 
-     * characters.
-     * TODO: Figure out what exactly is going on, and what is a safe number, and 
-     * why.
-     * TODO: Figure out good places to split this.
-     */
-    for (unsigned int i = 0; i < ranges.Length(); i++) {
-        if (ranges[i].Length() > MAX_RANGE_LENGTH) {
-            ranges.InsertElementAt(i + 1, 
-                                   gfxTextRange(ranges[i].start 
-                                     + MAX_RANGE_LENGTH,
-                                   ranges[i].end));
-            ranges[i + 1].font = ranges[i].font;
-            ranges[i].end = ranges[i].start + MAX_RANGE_LENGTH;
-        }
-    }
-    UINT32 rangeOffset = 0;
-    for (unsigned int i = 0; i < ranges.Length(); i++) {
-        gfxTextRange &range = ranges[i];
-        TextAnalysis analysis(
-            aString + range.start, range.Length(),
-            NULL, 
-            readingDirection);
-        TextAnalysis::Run *runHead;
-        DWRITE_LINE_BREAKPOINT *linebreaks;
-        hr = analysis.GenerateResults(analyzer, &runHead, &linebreaks);
-
-        if (FAILED(hr)) {
-            NS_WARNING("Analyzer failed to generate results.");
-            continue;
-        }
-
-        if (range.font) {
-            font = static_cast<gfxDWriteFont*>(range.font.get());
-        } else {
-            // XXX missing glyph info needs to be set
-            font = GetFontAt(0);
-        }
-
-        textRun->AddGlyphRun(font, range.start);
-
-        PRUint32 appUnitsPerDevPixel = textRun->GetAppUnitsPerDevUnit();
-
-        UINT32 maxGlyphs = 0;
-trymoreglyphs:
-        if ((PR_UINT32_MAX - 3 * range.Length() / 2 + 16) < maxGlyphs) {
-            // This isn't going to work, we're going to cross the UINT32 upper
-            // limit. Next range it is.
-            continue;
-        }
-        maxGlyphs += 3 * range.Length() / 2 + 16;
-
-        nsAutoTArray<UINT16, 400> clusters;
-        nsAutoTArray<UINT16, 400> indices;
-        nsAutoTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
-        nsAutoTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
-        if (!clusters.SetLength(range.Length()) ||
-            !indices.SetLength(maxGlyphs) || 
-            !textProperties.SetLength(maxGlyphs) ||
-            !glyphProperties.SetLength(maxGlyphs)) {
-                continue;
-        }
-
-        UINT32 actualGlyphs;
-
-        hr = analyzer->GetGlyphs(aString + range.start, range.Length(),
-            font->mFontFace, FALSE, 
-            readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
-            &runHead->mScript, NULL, NULL, NULL, NULL, 0,
-            maxGlyphs, clusters.Elements(), textProperties.Elements(),
-            indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
-
-        if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
-            // We increase the amount of glyphs and try again.
-            goto trymoreglyphs;
-        }
-        if (FAILED(hr)) {
-            NS_WARNING("Analyzer failed to get glyphs.");
-            continue;
-        }
-
-        WORD gID = indices[0];
-        nsAutoTArray<FLOAT, 400> advances;
-        nsAutoTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
-        if (!advances.SetLength(actualGlyphs) || 
-            !glyphOffsets.SetLength(actualGlyphs)) {
-            continue;
-        }
-
-        hr = analyzer->GetGlyphPlacements(aString + range.start, 
-                                          clusters.Elements(),
-                                          textProperties.Elements(),
-                                          range.Length(),
-                                          indices.Elements(),
-                                          glyphProperties.Elements(),
-                                          actualGlyphs,
-                                          font->mFontFace,
-                                          (float)font->GetAdjustedSize(),
-                                          FALSE,
-                                          FALSE,
-                                          &runHead->mScript,
-                                          NULL,
-                                          NULL,
-                                          NULL,
-                                          0,
-                                          advances.Elements(),
-                                          glyphOffsets.Elements());
-        if (FAILED(hr)) {
-            NS_WARNING("Analyzer failed to get glyph placements.");
-            continue;
-        }
-
-        nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
-
-        for (unsigned int c = 0; c < range.Length(); c++) {
-            PRUint32 k = clusters[c];
-            PRUint32 absC = range.start + c;
-
-            if (c > 0 && k == clusters[c - 1]) {
-                g.SetComplex(textRun->IsClusterStart(absC), PR_FALSE, 0);
-                textRun->SetGlyphs(absC, g, nsnull);
-                // This is a cluster continuation. No glyph here.
-                continue;
-            }
-
-            // Count glyphs for this character
-            PRUint32 glyphCount = actualGlyphs - k;
-            PRUint32 nextClusterOffset;
-            for (nextClusterOffset = c + 1; 
-                nextClusterOffset < range.Length(); ++nextClusterOffset) {
-                if (clusters[nextClusterOffset] > k) {
-                    glyphCount = clusters[nextClusterOffset] - k;
-                    break;
-                }
-            }
-            PRInt32 advance = 
-                (PRInt32)(advances[k] * aParams->mAppUnitsPerDevUnit);
-            if (glyphCount == 1 && advance >= 0 &&
-                glyphOffsets[k].advanceOffset == 0 &&
-                glyphOffsets[k].ascenderOffset == 0 &&
-                textRun->IsClusterStart(absC) &&
-                gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
-                gfxTextRun::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
-                  textRun->SetSimpleGlyph(absC, 
-                                          g.SetSimpleGlyph(advance, 
-                                                           indices[k]));
-            } else {
-                if (detailedGlyphs.Length() < glyphCount) {
-                    if (!detailedGlyphs.AppendElements(
-                        glyphCount - detailedGlyphs.Length())) {
-                        continue;
-                    }
-                }
-                float totalAdvance = 0;
-                for (unsigned int z = 0; z < glyphCount; z++) {
-                    detailedGlyphs[z].mGlyphID = indices[k + z];
-                    detailedGlyphs[z].mAdvance = 
-                        (PRInt32)(advances[k + z]
-                           * aParams->mAppUnitsPerDevUnit);
-                    if (readingDirection == 
-                        DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
-                        detailedGlyphs[z].mXOffset = 
-                            (totalAdvance + 
-                              glyphOffsets[k + z].advanceOffset)
-                            * aParams->mAppUnitsPerDevUnit;
-                    } else {
-                        detailedGlyphs[z].mXOffset = 
-                            glyphOffsets[k + z].advanceOffset *
-                            aParams->mAppUnitsPerDevUnit;
-                    }
-                    detailedGlyphs[z].mYOffset = 
-                        -glyphOffsets[k + z].ascenderOffset *
-                        aParams->mAppUnitsPerDevUnit;
-                    totalAdvance += advances[k + z];
-                }
-                textRun->SetGlyphs(
-                    absC,
-                    g.SetComplex(textRun->IsClusterStart(absC),
-                                 PR_TRUE,
-                                 glyphCount),
-                    detailedGlyphs.Elements());
-            }
-        }
-    }
-
-    return textRun;
-}
-
-gfxTextRun *
-gfxDWriteFontGroup::MakeTextRun(const PRUint8 *aString,
-                                PRUint32 aLength,
-                                const Parameters *aParams,
-                                PRUint32 aFlags)
-{
-    nsCString string((const char*)aString, aLength);
-    return MakeTextRun(NS_ConvertASCIItoUTF16(string).get(),
-                       aLength,
-                       aParams,
-                       aFlags);
-}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxDWriteShaper.cpp
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Foundation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "gfxDWriteShaper.h"
+#include "gfxWindowsPlatform.h"
+
+#include <dwrite.h>
+
+#include "gfxDWriteTextAnalysis.h"
+
+
+#define MAX_RANGE_LENGTH 25000
+
+PRBool
+gfxDWriteShaper::InitTextRun(gfxContext *aContext,
+                             gfxTextRun *aTextRun,
+                             const PRUnichar *aString,
+                             PRUint32 aRunStart,
+                             PRUint32 aRunLength)
+{
+    HRESULT hr;
+    // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
+
+    DWRITE_READING_DIRECTION readingDirection = 
+        aTextRun->IsRightToLeft()
+            ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
+            : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+    gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
+
+    gfxTextRun::CompressedGlyph g;
+
+    nsRefPtr<IDWriteTextAnalyzer> analyzer;
+
+    hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
+        CreateTextAnalyzer(getter_AddRefs(analyzer));
+    if (FAILED(hr)) {
+        return PR_FALSE;
+    }
+
+    /**
+     * There's an internal 16-bit limit on some things inside the analyzer.
+     * to be on the safe side here we split up any ranges over MAX_RANGE_LENGTH 
+     * characters.
+     * TODO: Figure out what exactly is going on, and what is a safe number, and 
+     * why.
+     * TODO: Figure out good places to split this.
+     */
+/*
+    for (unsigned int i = 0; i < ranges.Length(); i++) {
+        if (ranges[i].Length() > MAX_RANGE_LENGTH) {
+            ranges.InsertElementAt(i + 1, 
+                                   gfxTextRange(ranges[i].start 
+                                     + MAX_RANGE_LENGTH,
+                                   ranges[i].end));
+            ranges[i + 1].font = ranges[i].font;
+            ranges[i].end = ranges[i].start + MAX_RANGE_LENGTH;
+        }
+    }
+    UINT32 rangeOffset = 0;
+*/
+ //   for (unsigned int i = 0; i < ranges.Length(); i++) {
+ //       gfxTextRange &range = ranges[i];
+    PRBool result = PR_TRUE;
+    do {
+        gfxTextRange range(aRunStart, aRunStart + aRunLength);
+        TextAnalysis analysis(
+            aString + range.start, range.Length(),
+            NULL, 
+            readingDirection);
+        TextAnalysis::Run *runHead;
+        DWRITE_LINE_BREAKPOINT *linebreaks;
+        hr = analysis.GenerateResults(analyzer, &runHead, &linebreaks);
+
+        if (FAILED(hr)) {
+            NS_WARNING("Analyzer failed to generate results.");
+            result = PR_FALSE;
+            break;
+        }
+
+        PRUint32 appUnitsPerDevPixel = aTextRun->GetAppUnitsPerDevUnit();
+
+        UINT32 maxGlyphs = 0;
+trymoreglyphs:
+        if ((PR_UINT32_MAX - 3 * range.Length() / 2 + 16) < maxGlyphs) {
+            // This isn't going to work, we're going to cross the UINT32 upper
+            // limit. Next range it is.
+            continue;
+        }
+        maxGlyphs += 3 * range.Length() / 2 + 16;
+
+        nsAutoTArray<UINT16, 400> clusters;
+        nsAutoTArray<UINT16, 400> indices;
+        nsAutoTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
+        nsAutoTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
+        if (!clusters.SetLength(range.Length()) ||
+            !indices.SetLength(maxGlyphs) || 
+            !textProperties.SetLength(maxGlyphs) ||
+            !glyphProperties.SetLength(maxGlyphs)) {
+                continue;
+        }
+
+        UINT32 actualGlyphs;
+
+        hr = analyzer->GetGlyphs(aString + range.start, range.Length(),
+            font->GetFontFace(), FALSE, 
+            readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
+            &runHead->mScript, NULL, NULL, NULL, NULL, 0,
+            maxGlyphs, clusters.Elements(), textProperties.Elements(),
+            indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
+
+        if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+            // We increase the amount of glyphs and try again.
+            goto trymoreglyphs;
+        }
+        if (FAILED(hr)) {
+            NS_WARNING("Analyzer failed to get glyphs.");
+            result = PR_FALSE;
+            break;
+        }
+
+        WORD gID = indices[0];
+        nsAutoTArray<FLOAT, 400> advances;
+        nsAutoTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
+        if (!advances.SetLength(actualGlyphs) || 
+            !glyphOffsets.SetLength(actualGlyphs)) {
+            continue;
+        }
+
+        hr = analyzer->GetGlyphPlacements(aString + range.start, 
+                                          clusters.Elements(),
+                                          textProperties.Elements(),
+                                          range.Length(),
+                                          indices.Elements(),
+                                          glyphProperties.Elements(),
+                                          actualGlyphs,
+                                          font->GetFontFace(),
+                                          font->GetAdjustedSize(),
+                                          FALSE,
+                                          FALSE,
+                                          &runHead->mScript,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          0,
+                                          advances.Elements(),
+                                          glyphOffsets.Elements());
+        if (FAILED(hr)) {
+            NS_WARNING("Analyzer failed to get glyph placements.");
+            result = PR_FALSE;
+            break;
+        }
+
+        nsAutoTArray<gfxTextRun::DetailedGlyph,1> detailedGlyphs;
+
+        for (unsigned int c = 0; c < range.Length(); c++) {
+            PRUint32 k = clusters[c];
+            PRUint32 absC = range.start + c;
+
+            if (c > 0 && k == clusters[c - 1]) {
+                g.SetComplex(aTextRun->IsClusterStart(absC), PR_FALSE, 0);
+                aTextRun->SetGlyphs(absC, g, nsnull);
+                // This is a cluster continuation. No glyph here.
+                continue;
+            }
+
+            // Count glyphs for this character
+            PRUint32 glyphCount = actualGlyphs - k;
+            PRUint32 nextClusterOffset;
+            for (nextClusterOffset = c + 1; 
+                nextClusterOffset < range.Length(); ++nextClusterOffset) {
+                if (clusters[nextClusterOffset] > k) {
+                    glyphCount = clusters[nextClusterOffset] - k;
+                    break;
+                }
+            }
+            PRInt32 advance = (PRInt32)(advances[k] * appUnitsPerDevPixel);
+            if (glyphCount == 1 && advance >= 0 &&
+                glyphOffsets[k].advanceOffset == 0 &&
+                glyphOffsets[k].ascenderOffset == 0 &&
+                aTextRun->IsClusterStart(absC) &&
+                gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
+                gfxTextRun::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
+                  aTextRun->SetSimpleGlyph(absC, 
+                                          g.SetSimpleGlyph(advance, 
+                                                           indices[k]));
+            } else {
+                if (detailedGlyphs.Length() < glyphCount) {
+                    if (!detailedGlyphs.AppendElements(
+                        glyphCount - detailedGlyphs.Length())) {
+                        continue;
+                    }
+                }
+                float totalAdvance = 0;
+                for (unsigned int z = 0; z < glyphCount; z++) {
+                    detailedGlyphs[z].mGlyphID = indices[k + z];
+                    detailedGlyphs[z].mAdvance = 
+                        (PRInt32)(advances[k + z]
+                           * appUnitsPerDevPixel);
+                    if (readingDirection == 
+                        DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
+                        detailedGlyphs[z].mXOffset = 
+                            (totalAdvance + 
+                              glyphOffsets[k + z].advanceOffset)
+                            * appUnitsPerDevPixel;
+                    } else {
+                        detailedGlyphs[z].mXOffset = 
+                            glyphOffsets[k + z].advanceOffset *
+                            appUnitsPerDevPixel;
+                    }
+                    detailedGlyphs[z].mYOffset = 
+                        -glyphOffsets[k + z].ascenderOffset *
+                        appUnitsPerDevPixel;
+                    totalAdvance += advances[k + z];
+                }
+                aTextRun->SetGlyphs(
+                    absC,
+                    g.SetComplex(aTextRun->IsClusterStart(absC),
+                                 PR_TRUE,
+                                 glyphCount),
+                    detailedGlyphs.Elements());
+            }
+        }
+    } while (0);
+
+    return result;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxDWriteShaper.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Foundation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_DWRITESHAPER_H
+#define GFX_DWRITESHAPER_H
+
+#include "gfxDWriteFonts.h"
+
+/**
+ * \brief Class representing a DWrite font shaper.
+ */
+class gfxDWriteShaper : public gfxFontShaper
+{
+public:
+    gfxDWriteShaper(gfxDWriteFont *aFont)
+        : gfxFontShaper(aFont)
+    { }
+
+    virtual ~gfxDWriteShaper() { }
+
+    virtual PRBool InitTextRun(gfxContext *aContext,
+                               gfxTextRun *aTextRun,
+                               const PRUnichar *aString,
+                               PRUint32 aRunStart,
+                               PRUint32 aRunLength);
+};
+
+#endif /* GFX_DWRITESHAPER_H */
--- a/gfx/thebes/src/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/src/gfxWindowsPlatform.cpp
@@ -309,25 +309,17 @@ gfxWindowsPlatform::GetStandardFamilyNam
 gfxFontGroup *
 gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
                                     const gfxFontStyle *aStyle,
                                     gfxUserFontSet *aUserFontSet)
 {
 #ifdef MOZ_FT2_FONTS
     return new gfxFT2FontGroup(aFamilies, aStyle);
 #else
-#ifdef CAIRO_HAS_DWRITE_FONT
-    if (GetDWriteFactory()) {
-        return new gfxDWriteFontGroup(aFamilies, aStyle, aUserFontSet);
-    } else {
-#endif
-        return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
-#ifdef CAIRO_HAS_DWRITE_FONT
-    }
-#endif
+    return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
 #endif
 }
 
 gfxFontEntry* 
 gfxWindowsPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
                                     const nsAString& aFontName)
 {
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,