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 +}