gfx/thebes/gfxDWriteShaper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxDWriteShaper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,230 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "gfxDWriteShaper.h"
    1.10 +#include "gfxWindowsPlatform.h"
    1.11 +
    1.12 +#include <dwrite.h>
    1.13 +
    1.14 +#include "gfxDWriteTextAnalysis.h"
    1.15 +
    1.16 +#include "nsCRT.h"
    1.17 +
    1.18 +bool
    1.19 +gfxDWriteShaper::ShapeText(gfxContext      *aContext,
    1.20 +                           const char16_t *aText,
    1.21 +                           uint32_t         aOffset,
    1.22 +                           uint32_t         aLength,
    1.23 +                           int32_t          aScript,
    1.24 +                           gfxShapedText   *aShapedText)
    1.25 +{
    1.26 +    HRESULT hr;
    1.27 +    // TODO: Handle TEXT_DISABLE_OPTIONAL_LIGATURES
    1.28 +
    1.29 +    DWRITE_READING_DIRECTION readingDirection = 
    1.30 +        aShapedText->IsRightToLeft()
    1.31 +            ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
    1.32 +            : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
    1.33 +
    1.34 +    gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
    1.35 +
    1.36 +    gfxShapedText::CompressedGlyph g;
    1.37 +
    1.38 +    IDWriteTextAnalyzer *analyzer =
    1.39 +        gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
    1.40 +    if (!analyzer) {
    1.41 +        return false;
    1.42 +    }
    1.43 +
    1.44 +    /**
    1.45 +     * There's an internal 16-bit limit on some things inside the analyzer,
    1.46 +     * but we never attempt to shape a word longer than 32K characters
    1.47 +     * in a single call, so we cannot exceed that limit.
    1.48 +     */
    1.49 +    UINT32 length = aLength;
    1.50 +    char16ptr_t text = aText;
    1.51 +
    1.52 +    TextAnalysis analysis(text, length, nullptr, readingDirection);
    1.53 +    TextAnalysis::Run *runHead;
    1.54 +    hr = analysis.GenerateResults(analyzer, &runHead);
    1.55 +
    1.56 +    if (FAILED(hr)) {
    1.57 +        NS_WARNING("Analyzer failed to generate results.");
    1.58 +        return false;
    1.59 +    }
    1.60 +
    1.61 +    int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
    1.62 +
    1.63 +    UINT32 maxGlyphs = 0;
    1.64 +trymoreglyphs:
    1.65 +    if ((UINT32_MAX - 3 * length / 2 + 16) < maxGlyphs) {
    1.66 +        // This isn't going to work, we're going to cross the UINT32 upper
    1.67 +        // limit. Give up.
    1.68 +        NS_WARNING("Shaper needs to generate more than 2^32 glyphs?!");
    1.69 +        return false;
    1.70 +    }
    1.71 +    maxGlyphs += 3 * length / 2 + 16;
    1.72 +
    1.73 +    AutoFallibleTArray<UINT16, 400> clusters;
    1.74 +    AutoFallibleTArray<UINT16, 400> indices;
    1.75 +    AutoFallibleTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
    1.76 +    AutoFallibleTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
    1.77 +    if (!clusters.SetLength(length) ||
    1.78 +        !indices.SetLength(maxGlyphs) || 
    1.79 +        !textProperties.SetLength(maxGlyphs) ||
    1.80 +        !glyphProperties.SetLength(maxGlyphs)) {
    1.81 +        NS_WARNING("Shaper failed to allocate memory.");
    1.82 +        return false;
    1.83 +    }
    1.84 +
    1.85 +    UINT32 actualGlyphs;
    1.86 +
    1.87 +    hr = analyzer->GetGlyphs(text, length,
    1.88 +            font->GetFontFace(), FALSE, 
    1.89 +            readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
    1.90 +            &runHead->mScript, nullptr, nullptr, nullptr, nullptr, 0,
    1.91 +            maxGlyphs, clusters.Elements(), textProperties.Elements(),
    1.92 +            indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
    1.93 +
    1.94 +    if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
    1.95 +        // We increase the amount of glyphs and try again.
    1.96 +        goto trymoreglyphs;
    1.97 +    }
    1.98 +    if (FAILED(hr)) {
    1.99 +        NS_WARNING("Analyzer failed to get glyphs.");
   1.100 +        return false;
   1.101 +    }
   1.102 +
   1.103 +    WORD gID = indices[0];
   1.104 +    AutoFallibleTArray<FLOAT, 400> advances;
   1.105 +    AutoFallibleTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
   1.106 +    if (!advances.SetLength(actualGlyphs) || 
   1.107 +        !glyphOffsets.SetLength(actualGlyphs)) {
   1.108 +        NS_WARNING("Shaper failed to allocate memory.");
   1.109 +        return false;
   1.110 +    }
   1.111 +
   1.112 +    if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
   1.113 +        hr = analyzer->GetGdiCompatibleGlyphPlacements(
   1.114 +                                          text,
   1.115 +                                          clusters.Elements(),
   1.116 +                                          textProperties.Elements(),
   1.117 +                                          length,
   1.118 +                                          indices.Elements(),
   1.119 +                                          glyphProperties.Elements(),
   1.120 +                                          actualGlyphs,
   1.121 +                                          font->GetFontFace(),
   1.122 +                                          font->GetAdjustedSize(),
   1.123 +                                          1.0,
   1.124 +                                          nullptr,
   1.125 +                                          FALSE,
   1.126 +                                          FALSE,
   1.127 +                                          FALSE,
   1.128 +                                          &runHead->mScript,
   1.129 +                                          nullptr,
   1.130 +                                          nullptr,
   1.131 +                                          nullptr,
   1.132 +                                          0,
   1.133 +                                          advances.Elements(),
   1.134 +                                          glyphOffsets.Elements());
   1.135 +    } else {
   1.136 +        hr = analyzer->GetGlyphPlacements(text,
   1.137 +                                          clusters.Elements(),
   1.138 +                                          textProperties.Elements(),
   1.139 +                                          length,
   1.140 +                                          indices.Elements(),
   1.141 +                                          glyphProperties.Elements(),
   1.142 +                                          actualGlyphs,
   1.143 +                                          font->GetFontFace(),
   1.144 +                                          font->GetAdjustedSize(),
   1.145 +                                          FALSE,
   1.146 +                                          FALSE,
   1.147 +                                          &runHead->mScript,
   1.148 +                                          nullptr,
   1.149 +                                          nullptr,
   1.150 +                                          nullptr,
   1.151 +                                          0,
   1.152 +                                          advances.Elements(),
   1.153 +                                          glyphOffsets.Elements());
   1.154 +    }
   1.155 +    if (FAILED(hr)) {
   1.156 +        NS_WARNING("Analyzer failed to get glyph placements.");
   1.157 +        return false;
   1.158 +    }
   1.159 +
   1.160 +    nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
   1.161 +    gfxShapedText::CompressedGlyph *charGlyphs =
   1.162 +        aShapedText->GetCharacterGlyphs();
   1.163 +
   1.164 +    for (unsigned int c = 0; c < length; c++) {
   1.165 +        uint32_t k = clusters[c];
   1.166 +        uint32_t absC = aOffset + c;
   1.167 +
   1.168 +        if (c > 0 && k == clusters[c - 1]) {
   1.169 +            // This is a cluster continuation. No glyph here.
   1.170 +            gfxShapedText::CompressedGlyph &g = charGlyphs[absC];
   1.171 +            NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
   1.172 +            g.SetComplex(g.IsClusterStart(), false, 0);
   1.173 +            continue;
   1.174 +        }
   1.175 +
   1.176 +        // Count glyphs for this character
   1.177 +        uint32_t glyphCount = actualGlyphs - k;
   1.178 +        uint32_t nextClusterOffset;
   1.179 +        for (nextClusterOffset = c + 1; 
   1.180 +            nextClusterOffset < length; ++nextClusterOffset) {
   1.181 +            if (clusters[nextClusterOffset] > k) {
   1.182 +                glyphCount = clusters[nextClusterOffset] - k;
   1.183 +                break;
   1.184 +            }
   1.185 +        }
   1.186 +        int32_t advance = (int32_t)(advances[k] * appUnitsPerDevPixel);
   1.187 +        if (glyphCount == 1 && advance >= 0 &&
   1.188 +            glyphOffsets[k].advanceOffset == 0 &&
   1.189 +            glyphOffsets[k].ascenderOffset == 0 &&
   1.190 +            charGlyphs[absC].IsClusterStart() &&
   1.191 +            gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
   1.192 +            gfxShapedText::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
   1.193 +              charGlyphs[absC].SetSimpleGlyph(advance, indices[k]);
   1.194 +        } else {
   1.195 +            if (detailedGlyphs.Length() < glyphCount) {
   1.196 +                if (!detailedGlyphs.AppendElements(
   1.197 +                    glyphCount - detailedGlyphs.Length())) {
   1.198 +                    continue;
   1.199 +                }
   1.200 +            }
   1.201 +            float totalAdvance = 0;
   1.202 +            for (unsigned int z = 0; z < glyphCount; z++) {
   1.203 +                detailedGlyphs[z].mGlyphID = indices[k + z];
   1.204 +                detailedGlyphs[z].mAdvance = 
   1.205 +                    (int32_t)(advances[k + z]
   1.206 +                       * appUnitsPerDevPixel);
   1.207 +                if (readingDirection == 
   1.208 +                    DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
   1.209 +                    detailedGlyphs[z].mXOffset = 
   1.210 +                        (totalAdvance + 
   1.211 +                          glyphOffsets[k + z].advanceOffset)
   1.212 +                        * appUnitsPerDevPixel;
   1.213 +                } else {
   1.214 +                    detailedGlyphs[z].mXOffset = 
   1.215 +                        glyphOffsets[k + z].advanceOffset *
   1.216 +                        appUnitsPerDevPixel;
   1.217 +                }
   1.218 +                detailedGlyphs[z].mYOffset = 
   1.219 +                    -glyphOffsets[k + z].ascenderOffset *
   1.220 +                    appUnitsPerDevPixel;
   1.221 +                totalAdvance += advances[k + z];
   1.222 +            }
   1.223 +            aShapedText->SetGlyphs(
   1.224 +                absC,
   1.225 +                g.SetComplex(charGlyphs[absC].IsClusterStart(),
   1.226 +                             true,
   1.227 +                             glyphCount),
   1.228 +                detailedGlyphs.Elements());
   1.229 +        }
   1.230 +    }
   1.231 +
   1.232 +    return true;
   1.233 +}

mercurial