gfx/thebes/gfxDWriteShaper.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "gfxDWriteShaper.h"
     7 #include "gfxWindowsPlatform.h"
     9 #include <dwrite.h>
    11 #include "gfxDWriteTextAnalysis.h"
    13 #include "nsCRT.h"
    15 bool
    16 gfxDWriteShaper::ShapeText(gfxContext      *aContext,
    17                            const char16_t *aText,
    18                            uint32_t         aOffset,
    19                            uint32_t         aLength,
    20                            int32_t          aScript,
    21                            gfxShapedText   *aShapedText)
    22 {
    23     HRESULT hr;
    24     // TODO: Handle TEXT_DISABLE_OPTIONAL_LIGATURES
    26     DWRITE_READING_DIRECTION readingDirection = 
    27         aShapedText->IsRightToLeft()
    28             ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
    29             : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
    31     gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
    33     gfxShapedText::CompressedGlyph g;
    35     IDWriteTextAnalyzer *analyzer =
    36         gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
    37     if (!analyzer) {
    38         return false;
    39     }
    41     /**
    42      * There's an internal 16-bit limit on some things inside the analyzer,
    43      * but we never attempt to shape a word longer than 32K characters
    44      * in a single call, so we cannot exceed that limit.
    45      */
    46     UINT32 length = aLength;
    47     char16ptr_t text = aText;
    49     TextAnalysis analysis(text, length, nullptr, readingDirection);
    50     TextAnalysis::Run *runHead;
    51     hr = analysis.GenerateResults(analyzer, &runHead);
    53     if (FAILED(hr)) {
    54         NS_WARNING("Analyzer failed to generate results.");
    55         return false;
    56     }
    58     int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
    60     UINT32 maxGlyphs = 0;
    61 trymoreglyphs:
    62     if ((UINT32_MAX - 3 * length / 2 + 16) < maxGlyphs) {
    63         // This isn't going to work, we're going to cross the UINT32 upper
    64         // limit. Give up.
    65         NS_WARNING("Shaper needs to generate more than 2^32 glyphs?!");
    66         return false;
    67     }
    68     maxGlyphs += 3 * length / 2 + 16;
    70     AutoFallibleTArray<UINT16, 400> clusters;
    71     AutoFallibleTArray<UINT16, 400> indices;
    72     AutoFallibleTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
    73     AutoFallibleTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
    74     if (!clusters.SetLength(length) ||
    75         !indices.SetLength(maxGlyphs) || 
    76         !textProperties.SetLength(maxGlyphs) ||
    77         !glyphProperties.SetLength(maxGlyphs)) {
    78         NS_WARNING("Shaper failed to allocate memory.");
    79         return false;
    80     }
    82     UINT32 actualGlyphs;
    84     hr = analyzer->GetGlyphs(text, length,
    85             font->GetFontFace(), FALSE, 
    86             readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
    87             &runHead->mScript, nullptr, nullptr, nullptr, nullptr, 0,
    88             maxGlyphs, clusters.Elements(), textProperties.Elements(),
    89             indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
    91     if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
    92         // We increase the amount of glyphs and try again.
    93         goto trymoreglyphs;
    94     }
    95     if (FAILED(hr)) {
    96         NS_WARNING("Analyzer failed to get glyphs.");
    97         return false;
    98     }
   100     WORD gID = indices[0];
   101     AutoFallibleTArray<FLOAT, 400> advances;
   102     AutoFallibleTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
   103     if (!advances.SetLength(actualGlyphs) || 
   104         !glyphOffsets.SetLength(actualGlyphs)) {
   105         NS_WARNING("Shaper failed to allocate memory.");
   106         return false;
   107     }
   109     if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
   110         hr = analyzer->GetGdiCompatibleGlyphPlacements(
   111                                           text,
   112                                           clusters.Elements(),
   113                                           textProperties.Elements(),
   114                                           length,
   115                                           indices.Elements(),
   116                                           glyphProperties.Elements(),
   117                                           actualGlyphs,
   118                                           font->GetFontFace(),
   119                                           font->GetAdjustedSize(),
   120                                           1.0,
   121                                           nullptr,
   122                                           FALSE,
   123                                           FALSE,
   124                                           FALSE,
   125                                           &runHead->mScript,
   126                                           nullptr,
   127                                           nullptr,
   128                                           nullptr,
   129                                           0,
   130                                           advances.Elements(),
   131                                           glyphOffsets.Elements());
   132     } else {
   133         hr = analyzer->GetGlyphPlacements(text,
   134                                           clusters.Elements(),
   135                                           textProperties.Elements(),
   136                                           length,
   137                                           indices.Elements(),
   138                                           glyphProperties.Elements(),
   139                                           actualGlyphs,
   140                                           font->GetFontFace(),
   141                                           font->GetAdjustedSize(),
   142                                           FALSE,
   143                                           FALSE,
   144                                           &runHead->mScript,
   145                                           nullptr,
   146                                           nullptr,
   147                                           nullptr,
   148                                           0,
   149                                           advances.Elements(),
   150                                           glyphOffsets.Elements());
   151     }
   152     if (FAILED(hr)) {
   153         NS_WARNING("Analyzer failed to get glyph placements.");
   154         return false;
   155     }
   157     nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
   158     gfxShapedText::CompressedGlyph *charGlyphs =
   159         aShapedText->GetCharacterGlyphs();
   161     for (unsigned int c = 0; c < length; c++) {
   162         uint32_t k = clusters[c];
   163         uint32_t absC = aOffset + c;
   165         if (c > 0 && k == clusters[c - 1]) {
   166             // This is a cluster continuation. No glyph here.
   167             gfxShapedText::CompressedGlyph &g = charGlyphs[absC];
   168             NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
   169             g.SetComplex(g.IsClusterStart(), false, 0);
   170             continue;
   171         }
   173         // Count glyphs for this character
   174         uint32_t glyphCount = actualGlyphs - k;
   175         uint32_t nextClusterOffset;
   176         for (nextClusterOffset = c + 1; 
   177             nextClusterOffset < length; ++nextClusterOffset) {
   178             if (clusters[nextClusterOffset] > k) {
   179                 glyphCount = clusters[nextClusterOffset] - k;
   180                 break;
   181             }
   182         }
   183         int32_t advance = (int32_t)(advances[k] * appUnitsPerDevPixel);
   184         if (glyphCount == 1 && advance >= 0 &&
   185             glyphOffsets[k].advanceOffset == 0 &&
   186             glyphOffsets[k].ascenderOffset == 0 &&
   187             charGlyphs[absC].IsClusterStart() &&
   188             gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
   189             gfxShapedText::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
   190               charGlyphs[absC].SetSimpleGlyph(advance, indices[k]);
   191         } else {
   192             if (detailedGlyphs.Length() < glyphCount) {
   193                 if (!detailedGlyphs.AppendElements(
   194                     glyphCount - detailedGlyphs.Length())) {
   195                     continue;
   196                 }
   197             }
   198             float totalAdvance = 0;
   199             for (unsigned int z = 0; z < glyphCount; z++) {
   200                 detailedGlyphs[z].mGlyphID = indices[k + z];
   201                 detailedGlyphs[z].mAdvance = 
   202                     (int32_t)(advances[k + z]
   203                        * appUnitsPerDevPixel);
   204                 if (readingDirection == 
   205                     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
   206                     detailedGlyphs[z].mXOffset = 
   207                         (totalAdvance + 
   208                           glyphOffsets[k + z].advanceOffset)
   209                         * appUnitsPerDevPixel;
   210                 } else {
   211                     detailedGlyphs[z].mXOffset = 
   212                         glyphOffsets[k + z].advanceOffset *
   213                         appUnitsPerDevPixel;
   214                 }
   215                 detailedGlyphs[z].mYOffset = 
   216                     -glyphOffsets[k + z].ascenderOffset *
   217                     appUnitsPerDevPixel;
   218                 totalAdvance += advances[k + z];
   219             }
   220             aShapedText->SetGlyphs(
   221                 absC,
   222                 g.SetComplex(charGlyphs[absC].IsClusterStart(),
   223                              true,
   224                              glyphCount),
   225                 detailedGlyphs.Elements());
   226         }
   227     }
   229     return true;
   230 }

mercurial