OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2011 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "SkTypes.h" | |
9 #undef GetGlyphIndices | |
10 | |
11 #include "SkDWrite.h" | |
12 #include "SkDWriteGeometrySink.h" | |
13 #include "SkEndian.h" | |
14 #include "SkGlyph.h" | |
15 #include "SkHRESULT.h" | |
16 #include "SkMaskGamma.h" | |
17 #include "SkMatrix22.h" | |
18 #include "SkOTTable_EBLC.h" | |
19 #include "SkOTTable_EBSC.h" | |
20 #include "SkPath.h" | |
21 #include "SkScalerContext.h" | |
22 #include "SkScalerContext_win_dw.h" | |
23 #include "SkTScopedComPtr.h" | |
24 #include "SkTypeface_win_dw.h" | |
25 | |
26 #include <dwrite.h> | |
27 | |
28 static bool isLCD(const SkScalerContext::Rec& rec) { | |
29 return SkMask::kLCD16_Format == rec.fMaskFormat || | |
30 SkMask::kLCD32_Format == rec.fMaskFormat; | |
31 } | |
32 | |
33 static bool hasBitmapStrike(DWriteFontTypeface* typeface, int size) { | |
34 { | |
35 AutoTDWriteTable<SkOTTableEmbeddedBitmapLocation> eblc(typeface->fDWrite
FontFace.get()); | |
36 if (!eblc.fExists) { | |
37 return false; | |
38 } | |
39 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation)) { | |
40 return false; | |
41 } | |
42 if (eblc->version != SkOTTableEmbeddedBitmapLocation::version_initial) { | |
43 return false; | |
44 } | |
45 | |
46 uint32_t numSizes = SkEndianSwap32(eblc->numSizes); | |
47 if (eblc.fSize < sizeof(SkOTTableEmbeddedBitmapLocation) + | |
48 sizeof(SkOTTableEmbeddedBitmapLocation::BitmapSizeTable
) * numSizes) | |
49 { | |
50 return false; | |
51 } | |
52 | |
53 const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable* sizeTable = | |
54 SkTAfter<const SkOTTableEmbeddedBitmapLocation::BitmapSizeTable>
(eblc.get()); | |
55 for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { | |
56 if (sizeTable->ppemX == size && sizeTable->ppemY == size) { | |
57 // TODO: determine if we should dig through IndexSubTableArray/I
ndexSubTable | |
58 // to determine the actual number of glyphs with bitmaps. | |
59 | |
60 // TODO: Ensure that the bitmaps actually cover a significant po
rtion of the strike. | |
61 | |
62 //TODO: Endure that the bitmaps are bi-level. | |
63 if (sizeTable->endGlyphIndex >= sizeTable->startGlyphIndex + 3)
{ | |
64 return true; | |
65 } | |
66 } | |
67 } | |
68 } | |
69 | |
70 { | |
71 AutoTDWriteTable<SkOTTableEmbeddedBitmapScaling> ebsc(typeface->fDWriteF
ontFace.get()); | |
72 if (!ebsc.fExists) { | |
73 return false; | |
74 } | |
75 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling)) { | |
76 return false; | |
77 } | |
78 if (ebsc->version != SkOTTableEmbeddedBitmapScaling::version_initial) { | |
79 return false; | |
80 } | |
81 | |
82 uint32_t numSizes = SkEndianSwap32(ebsc->numSizes); | |
83 if (ebsc.fSize < sizeof(SkOTTableEmbeddedBitmapScaling) + | |
84 sizeof(SkOTTableEmbeddedBitmapScaling::BitmapScaleTable
) * numSizes) | |
85 { | |
86 return false; | |
87 } | |
88 | |
89 const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable* scaleTable = | |
90 SkTAfter<const SkOTTableEmbeddedBitmapScaling::BitmapScaleTable>
(ebsc.get()); | |
91 for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { | |
92 if (scaleTable->ppemX == size && scaleTable->ppemY == size) { | |
93 // EBSC tables are normally only found in bitmap only fonts. | |
94 return true; | |
95 } | |
96 } | |
97 } | |
98 | |
99 return false; | |
100 } | |
101 | |
102 static bool bothZero(SkScalar a, SkScalar b) { | |
103 return 0 == a && 0 == b; | |
104 } | |
105 | |
106 // returns false if there is any non-90-rotation or skew | |
107 static bool isAxisAligned(const SkScalerContext::Rec& rec) { | |
108 return 0 == rec.fPreSkewX && | |
109 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || | |
110 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); | |
111 } | |
112 | |
113 SkScalerContext_DW::SkScalerContext_DW(DWriteFontTypeface* typeface, | |
114 const SkDescriptor* desc) | |
115 : SkScalerContext(typeface, desc) | |
116 , fTypeface(SkRef(typeface)) | |
117 , fGlyphCount(-1) { | |
118 | |
119 // In general, all glyphs should use CLEARTYPE_NATURAL_SYMMETRIC | |
120 // except when bi-level rendering is requested or there are embedded | |
121 // bi-level bitmaps (and the embedded bitmap flag is set and no rotation). | |
122 // | |
123 // DirectWrite's IDWriteFontFace::GetRecommendedRenderingMode does not do | |
124 // this. As a result, determine the actual size of the text and then see if | |
125 // there are any embedded bi-level bitmaps of that size. If there are, then | |
126 // force bitmaps by requesting bi-level rendering. | |
127 // | |
128 // FreeType allows for separate ppemX and ppemY, but DirectWrite assumes | |
129 // square pixels and only uses ppemY. Therefore the transform must track any | |
130 // non-uniform x-scale. | |
131 // | |
132 // Also, rotated glyphs should have the same absolute advance widths as | |
133 // horizontal glyphs and the subpixel flag should not affect glyph shapes. | |
134 | |
135 // A is the total matrix. | |
136 SkMatrix A; | |
137 fRec.getSingleMatrix(&A); | |
138 | |
139 // h is where A maps the horizontal baseline. | |
140 SkPoint h = SkPoint::Make(SK_Scalar1, 0); | |
141 A.mapPoints(&h, 1); | |
142 | |
143 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0). | |
144 SkMatrix G; | |
145 SkComputeGivensRotation(h, &G); | |
146 | |
147 // GA is the matrix A with rotation removed. | |
148 SkMatrix GA(G); | |
149 GA.preConcat(A); | |
150 | |
151 // realTextSize is the actual device size we want (as opposed to the size th
e user requested). | |
152 // gdiTextSize is the size we request when GDI compatible. | |
153 // If the scale is negative, this means the matrix will do the flip anyway. | |
154 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); | |
155 // Due to floating point math, the lower bits are suspect. Round carefully. | |
156 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize * 64.0f) / 64.0f; | |
157 if (gdiTextSize == 0) { | |
158 gdiTextSize = SK_Scalar1; | |
159 } | |
160 | |
161 bool bitmapRequested = SkToBool(fRec.fFlags & SkScalerContext::kEmbeddedBitm
apText_Flag); | |
162 bool hasBitmap = false; | |
163 bool axisAlignedBitmap = false; | |
164 if (bitmapRequested) { | |
165 hasBitmap = hasBitmapStrike(typeface, SkScalarTruncToInt(gdiTextSize)); | |
166 axisAlignedBitmap = isAxisAligned(fRec); | |
167 } | |
168 | |
169 // If the user requested aliased, do so with aliased compatible metrics. | |
170 if (SkMask::kBW_Format == fRec.fMaskFormat) { | |
171 fTextSizeRender = gdiTextSize; | |
172 fRenderingMode = DWRITE_RENDERING_MODE_ALIASED; | |
173 fTextureType = DWRITE_TEXTURE_ALIASED_1x1; | |
174 fTextSizeMeasure = gdiTextSize; | |
175 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | |
176 | |
177 // If we can use a bitmap, use gdi classic rendering and measurement. | |
178 // This will not always provide a bitmap, but matches expected behavior. | |
179 } else if (hasBitmap && axisAlignedBitmap) { | |
180 fTextSizeRender = gdiTextSize; | |
181 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; | |
182 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | |
183 fTextSizeMeasure = gdiTextSize; | |
184 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | |
185 | |
186 // If rotated but the horizontal text could have used a bitmap, | |
187 // render high quality rotated glyphs but measure using bitmap metrics. | |
188 } else if (hasBitmap) { | |
189 fTextSizeRender = gdiTextSize; | |
190 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | |
191 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | |
192 fTextSizeMeasure = gdiTextSize; | |
193 fMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC; | |
194 | |
195 // The normal case is to use natural symmetric rendering and linear metrics. | |
196 } else { | |
197 fTextSizeRender = realTextSize; | |
198 fRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; | |
199 fTextureType = DWRITE_TEXTURE_CLEARTYPE_3x1; | |
200 fTextSizeMeasure = realTextSize; | |
201 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; | |
202 } | |
203 | |
204 if (this->isSubpixel()) { | |
205 fTextSizeMeasure = realTextSize; | |
206 fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; | |
207 } | |
208 | |
209 // Remove the realTextSize, as that is the text height scale currently in A. | |
210 SkScalar scale = SkScalarInvert(realTextSize); | |
211 | |
212 // fSkXform is the total matrix A without the text height scale. | |
213 fSkXform = A; | |
214 fSkXform.preScale(scale, scale); //remove the text height scale. | |
215 | |
216 fXform.m11 = SkScalarToFloat(fSkXform.getScaleX()); | |
217 fXform.m12 = SkScalarToFloat(fSkXform.getSkewY()); | |
218 fXform.m21 = SkScalarToFloat(fSkXform.getSkewX()); | |
219 fXform.m22 = SkScalarToFloat(fSkXform.getScaleY()); | |
220 fXform.dx = 0; | |
221 fXform.dy = 0; | |
222 | |
223 // GsA is the non-rotational part of A without the text height scale. | |
224 SkMatrix GsA(GA); | |
225 GsA.preScale(scale, scale); //remove text height scale, G is rotational so r
eorders with scale. | |
226 | |
227 fGsA.m11 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleX)); | |
228 fGsA.m12 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewY)); // This should be ~0
. | |
229 fGsA.m21 = SkScalarToFloat(GsA.get(SkMatrix::kMSkewX)); | |
230 fGsA.m22 = SkScalarToFloat(GsA.get(SkMatrix::kMScaleY)); | |
231 fGsA.dx = 0; | |
232 fGsA.dy = 0; | |
233 | |
234 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational. | |
235 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(Sk
Matrix::kMTransX), | |
236 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(Sk
Matrix::kMTransY), | |
237 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(Sk
Matrix::kMPersp2)); | |
238 } | |
239 | |
240 SkScalerContext_DW::~SkScalerContext_DW() { | |
241 } | |
242 | |
243 unsigned SkScalerContext_DW::generateGlyphCount() { | |
244 if (fGlyphCount < 0) { | |
245 fGlyphCount = fTypeface->fDWriteFontFace->GetGlyphCount(); | |
246 } | |
247 return fGlyphCount; | |
248 } | |
249 | |
250 uint16_t SkScalerContext_DW::generateCharToGlyph(SkUnichar uni) { | |
251 uint16_t index = 0; | |
252 fTypeface->fDWriteFontFace->GetGlyphIndices(reinterpret_cast<UINT32*>(&uni),
1, &index); | |
253 return index; | |
254 } | |
255 | |
256 void SkScalerContext_DW::generateAdvance(SkGlyph* glyph) { | |
257 //Delta is the difference between the right/left side bearing metric | |
258 //and where the right/left side bearing ends up after hinting. | |
259 //DirectWrite does not provide this information. | |
260 glyph->fRsbDelta = 0; | |
261 glyph->fLsbDelta = 0; | |
262 | |
263 glyph->fAdvanceX = 0; | |
264 glyph->fAdvanceY = 0; | |
265 | |
266 uint16_t glyphId = glyph->getGlyphID(); | |
267 DWRITE_GLYPH_METRICS gm; | |
268 | |
269 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || | |
270 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) | |
271 { | |
272 HRVM(fTypeface->fDWriteFontFace->GetGdiCompatibleGlyphMetrics( | |
273 fTextSizeMeasure, | |
274 1.0f, // pixelsPerDip | |
275 &fGsA, | |
276 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode, | |
277 &glyphId, 1, | |
278 &gm), | |
279 "Could not get gdi compatible glyph metrics."); | |
280 } else { | |
281 HRVM(fTypeface->fDWriteFontFace->GetDesignGlyphMetrics(&glyphId, 1, &gm)
, | |
282 "Could not get design metrics."); | |
283 } | |
284 | |
285 DWRITE_FONT_METRICS dwfm; | |
286 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); | |
287 SkScalar advanceX = SkScalarMulDiv(fTextSizeMeasure, | |
288 SkIntToScalar(gm.advanceWidth), | |
289 SkIntToScalar(dwfm.designUnitsPerEm)); | |
290 | |
291 if (!this->isSubpixel()) { | |
292 advanceX = SkScalarRoundToScalar(advanceX); | |
293 } | |
294 | |
295 SkVector vecs[1] = { { advanceX, 0 } }; | |
296 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || | |
297 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) | |
298 { | |
299 fG_inv.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); | |
300 } else { | |
301 fSkXform.mapVectors(vecs, SK_ARRAY_COUNT(vecs)); | |
302 } | |
303 | |
304 glyph->fAdvanceX = SkScalarToFixed(vecs[0].fX); | |
305 glyph->fAdvanceY = SkScalarToFixed(vecs[0].fY); | |
306 } | |
307 | |
308 void SkScalerContext_DW::generateMetrics(SkGlyph* glyph) { | |
309 glyph->fWidth = 0; | |
310 | |
311 this->generateAdvance(glyph); | |
312 | |
313 //Measure raster size. | |
314 fXform.dx = SkFixedToFloat(glyph->getSubXFixed()); | |
315 fXform.dy = SkFixedToFloat(glyph->getSubYFixed()); | |
316 | |
317 FLOAT advance = 0; | |
318 | |
319 UINT16 glyphId = glyph->getGlyphID(); | |
320 | |
321 DWRITE_GLYPH_OFFSET offset; | |
322 offset.advanceOffset = 0.0f; | |
323 offset.ascenderOffset = 0.0f; | |
324 | |
325 DWRITE_GLYPH_RUN run; | |
326 run.glyphCount = 1; | |
327 run.glyphAdvances = &advance; | |
328 run.fontFace = fTypeface->fDWriteFontFace.get(); | |
329 run.fontEmSize = SkScalarToFloat(fTextSizeRender); | |
330 run.bidiLevel = 0; | |
331 run.glyphIndices = &glyphId; | |
332 run.isSideways = FALSE; | |
333 run.glyphOffsets = &offset; | |
334 | |
335 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; | |
336 HRVM(fTypeface->fFactory->CreateGlyphRunAnalysis( | |
337 &run, | |
338 1.0f, // pixelsPerDip, | |
339 &fXform, | |
340 fRenderingMode, | |
341 fMeasuringMode, | |
342 0.0f, // baselineOriginX, | |
343 0.0f, // baselineOriginY, | |
344 &glyphRunAnalysis), | |
345 "Could not create glyph run analysis."); | |
346 | |
347 RECT bbox; | |
348 HRVM(glyphRunAnalysis->GetAlphaTextureBounds(fTextureType, &bbox), | |
349 "Could not get texture bounds."); | |
350 | |
351 glyph->fWidth = SkToU16(bbox.right - bbox.left); | |
352 glyph->fHeight = SkToU16(bbox.bottom - bbox.top); | |
353 glyph->fLeft = SkToS16(bbox.left); | |
354 glyph->fTop = SkToS16(bbox.top); | |
355 } | |
356 | |
357 void SkScalerContext_DW::generateFontMetrics(SkPaint::FontMetrics* mx, | |
358 SkPaint::FontMetrics* my) { | |
359 if (!(mx || my)) | |
360 return; | |
361 | |
362 if (mx) { | |
363 sk_bzero(mx, sizeof(*mx)); | |
364 } | |
365 if (my) { | |
366 sk_bzero(my, sizeof(*my)); | |
367 } | |
368 | |
369 DWRITE_FONT_METRICS dwfm; | |
370 if (DWRITE_MEASURING_MODE_GDI_CLASSIC == fMeasuringMode || | |
371 DWRITE_MEASURING_MODE_GDI_NATURAL == fMeasuringMode) | |
372 { | |
373 fTypeface->fDWriteFontFace->GetGdiCompatibleMetrics( | |
374 fTextSizeRender, | |
375 1.0f, // pixelsPerDip | |
376 &fXform, | |
377 &dwfm); | |
378 } else { | |
379 fTypeface->fDWriteFontFace->GetMetrics(&dwfm); | |
380 } | |
381 | |
382 SkScalar upem = SkIntToScalar(dwfm.designUnitsPerEm); | |
383 if (mx) { | |
384 mx->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; | |
385 mx->fAscent = mx->fTop; | |
386 mx->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; | |
387 mx->fBottom = mx->fDescent; | |
388 mx->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; | |
389 mx->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; | |
390 mx->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underline
Thickness) / upem; | |
391 mx->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlin
ePosition) / upem); | |
392 | |
393 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; | |
394 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; | |
395 } | |
396 | |
397 if (my) { | |
398 my->fTop = -fTextSizeRender * SkIntToScalar(dwfm.ascent) / upem; | |
399 my->fAscent = my->fTop; | |
400 my->fDescent = fTextSizeRender * SkIntToScalar(dwfm.descent) / upem; | |
401 my->fBottom = my->fDescent; | |
402 my->fLeading = fTextSizeRender * SkIntToScalar(dwfm.lineGap) / upem; | |
403 my->fXHeight = fTextSizeRender * SkIntToScalar(dwfm.xHeight) / upem; | |
404 my->fUnderlineThickness = fTextSizeRender * SkIntToScalar(dwfm.underline
Thickness) / upem; | |
405 my->fUnderlinePosition = -(fTextSizeRender * SkIntToScalar(dwfm.underlin
ePosition) / upem); | |
406 | |
407 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; | |
408 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; | |
409 } | |
410 } | |
411 | |
412 /////////////////////////////////////////////////////////////////////////////// | |
413 | |
414 #include "SkColorPriv.h" | |
415 | |
416 static void bilevel_to_bw(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph)
{ | |
417 const int width = glyph.fWidth; | |
418 const size_t dstRB = (width + 7) >> 3; | |
419 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); | |
420 | |
421 int byteCount = width >> 3; | |
422 int bitCount = width & 7; | |
423 | |
424 for (int y = 0; y < glyph.fHeight; ++y) { | |
425 if (byteCount > 0) { | |
426 for (int i = 0; i < byteCount; ++i) { | |
427 unsigned byte = 0; | |
428 byte |= src[0] & (1 << 7); | |
429 byte |= src[1] & (1 << 6); | |
430 byte |= src[2] & (1 << 5); | |
431 byte |= src[3] & (1 << 4); | |
432 byte |= src[4] & (1 << 3); | |
433 byte |= src[5] & (1 << 2); | |
434 byte |= src[6] & (1 << 1); | |
435 byte |= src[7] & (1 << 0); | |
436 dst[i] = byte; | |
437 src += 8; | |
438 } | |
439 } | |
440 if (bitCount > 0) { | |
441 unsigned byte = 0; | |
442 unsigned mask = 0x80; | |
443 for (int i = 0; i < bitCount; i++) { | |
444 byte |= (src[i]) & mask; | |
445 mask >>= 1; | |
446 } | |
447 dst[byteCount] = byte; | |
448 } | |
449 src += bitCount; | |
450 dst += dstRB; | |
451 } | |
452 } | |
453 | |
454 template<bool APPLY_PREBLEND> | |
455 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, cons
t uint8_t* table8) { | |
456 const size_t dstRB = glyph.rowBytes(); | |
457 const U16CPU width = glyph.fWidth; | |
458 uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage); | |
459 | |
460 for (U16CPU y = 0; y < glyph.fHeight; y++) { | |
461 for (U16CPU i = 0; i < width; i++) { | |
462 U8CPU r = *(src++); | |
463 U8CPU g = *(src++); | |
464 U8CPU b = *(src++); | |
465 dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8); | |
466 } | |
467 dst = (uint8_t*)((char*)dst + dstRB); | |
468 } | |
469 } | |
470 | |
471 template<bool APPLY_PREBLEND> | |
472 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, | |
473 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { | |
474 const size_t dstRB = glyph.rowBytes(); | |
475 const U16CPU width = glyph.fWidth; | |
476 uint16_t* SK_RESTRICT dst = static_cast<uint16_t*>(glyph.fImage); | |
477 | |
478 for (U16CPU y = 0; y < glyph.fHeight; y++) { | |
479 for (U16CPU i = 0; i < width; i++) { | |
480 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); | |
481 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); | |
482 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); | |
483 dst[i] = SkPack888ToRGB16(r, g, b); | |
484 } | |
485 dst = (uint16_t*)((char*)dst + dstRB); | |
486 } | |
487 } | |
488 | |
489 template<bool APPLY_PREBLEND> | |
490 static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, | |
491 const uint8_t* tableR, const uint8_t* tableG, const uin
t8_t* tableB) { | |
492 const size_t dstRB = glyph.rowBytes(); | |
493 const U16CPU width = glyph.fWidth; | |
494 SkPMColor* SK_RESTRICT dst = static_cast<SkPMColor*>(glyph.fImage); | |
495 | |
496 for (U16CPU y = 0; y < glyph.fHeight; y++) { | |
497 for (U16CPU i = 0; i < width; i++) { | |
498 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableR); | |
499 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableG); | |
500 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*(src++), tableB); | |
501 dst[i] = SkPackARGB32(0xFF, r, g, b); | |
502 } | |
503 dst = (SkPMColor*)((char*)dst + dstRB); | |
504 } | |
505 } | |
506 | |
507 const void* SkScalerContext_DW::drawDWMask(const SkGlyph& glyph) { | |
508 int sizeNeeded = glyph.fWidth * glyph.fHeight; | |
509 if (DWRITE_RENDERING_MODE_ALIASED != fRenderingMode) { | |
510 sizeNeeded *= 3; | |
511 } | |
512 if (sizeNeeded > fBits.count()) { | |
513 fBits.setCount(sizeNeeded); | |
514 } | |
515 | |
516 // erase | |
517 memset(fBits.begin(), 0, sizeNeeded); | |
518 | |
519 fXform.dx = SkFixedToFloat(glyph.getSubXFixed()); | |
520 fXform.dy = SkFixedToFloat(glyph.getSubYFixed()); | |
521 | |
522 FLOAT advance = 0.0f; | |
523 | |
524 UINT16 index = glyph.getGlyphID(); | |
525 | |
526 DWRITE_GLYPH_OFFSET offset; | |
527 offset.advanceOffset = 0.0f; | |
528 offset.ascenderOffset = 0.0f; | |
529 | |
530 DWRITE_GLYPH_RUN run; | |
531 run.glyphCount = 1; | |
532 run.glyphAdvances = &advance; | |
533 run.fontFace = fTypeface->fDWriteFontFace.get(); | |
534 run.fontEmSize = SkScalarToFloat(fTextSizeRender); | |
535 run.bidiLevel = 0; | |
536 run.glyphIndices = &index; | |
537 run.isSideways = FALSE; | |
538 run.glyphOffsets = &offset; | |
539 | |
540 SkTScopedComPtr<IDWriteGlyphRunAnalysis> glyphRunAnalysis; | |
541 HRNM(fTypeface->fFactory->CreateGlyphRunAnalysis(&run, | |
542 1.0f, // pixelsPerDip, | |
543 &fXform, | |
544 fRenderingMode, | |
545 fMeasuringMode, | |
546 0.0f, // baselineOriginX, | |
547 0.0f, // baselineOriginY, | |
548 &glyphRunAnalysis), | |
549 "Could not create glyph run analysis."); | |
550 | |
551 //NOTE: this assumes that the glyph has already been measured | |
552 //with an exact same glyph run analysis. | |
553 RECT bbox; | |
554 bbox.left = glyph.fLeft; | |
555 bbox.top = glyph.fTop; | |
556 bbox.right = glyph.fLeft + glyph.fWidth; | |
557 bbox.bottom = glyph.fTop + glyph.fHeight; | |
558 HRNM(glyphRunAnalysis->CreateAlphaTexture(fTextureType, | |
559 &bbox, | |
560 fBits.begin(), | |
561 sizeNeeded), | |
562 "Could not draw mask."); | |
563 return fBits.begin(); | |
564 } | |
565 | |
566 void SkScalerContext_DW::generateImage(const SkGlyph& glyph) { | |
567 //Create the mask. | |
568 const void* bits = this->drawDWMask(glyph); | |
569 if (!bits) { | |
570 sk_bzero(glyph.fImage, glyph.computeImageSize()); | |
571 return; | |
572 } | |
573 | |
574 //Copy the mask into the glyph. | |
575 const uint8_t* src = (const uint8_t*)bits; | |
576 if (DWRITE_RENDERING_MODE_ALIASED == fRenderingMode) { | |
577 bilevel_to_bw(src, glyph); | |
578 const_cast<SkGlyph&>(glyph).fMaskFormat = SkMask::kBW_Format; | |
579 } else if (!isLCD(fRec)) { | |
580 if (fPreBlend.isApplicable()) { | |
581 rgb_to_a8<true>(src, glyph, fPreBlend.fG); | |
582 } else { | |
583 rgb_to_a8<false>(src, glyph, fPreBlend.fG); | |
584 } | |
585 } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) { | |
586 if (fPreBlend.isApplicable()) { | |
587 rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend
.fB); | |
588 } else { | |
589 rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlen
d.fB); | |
590 } | |
591 } else { | |
592 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); | |
593 if (fPreBlend.isApplicable()) { | |
594 rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend
.fB); | |
595 } else { | |
596 rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlen
d.fB); | |
597 } | |
598 } | |
599 } | |
600 | |
601 void SkScalerContext_DW::generatePath(const SkGlyph& glyph, SkPath* path) { | |
602 SkASSERT(&glyph && path); | |
603 | |
604 path->reset(); | |
605 | |
606 SkTScopedComPtr<IDWriteGeometrySink> geometryToPath; | |
607 HRVM(SkDWriteGeometrySink::Create(path, &geometryToPath), | |
608 "Could not create geometry to path converter."); | |
609 uint16_t glyphId = glyph.getGlyphID(); | |
610 //TODO: convert to<->from DIUs? This would make a difference if hinting. | |
611 //It may not be needed, it appears that DirectWrite only hints at em size. | |
612 HRVM(fTypeface->fDWriteFontFace->GetGlyphRunOutline(SkScalarToFloat(fTextSiz
eRender), | |
613 &glyphId, | |
614 NULL, //advances | |
615 NULL, //offsets | |
616 1, //num glyphs | |
617 FALSE, //sideways | |
618 FALSE, //rtl | |
619 geometryToPath.get()), | |
620 "Could not create glyph outline."); | |
621 | |
622 path->transform(fSkXform); | |
623 } | |
OLD | NEW |