30
30
#include " config.h"
31
31
#include " platform/fonts/SimpleFontData.h"
32
32
33
+ #include " SkPaint.h"
34
+ #include " SkPath.h"
35
+ #include " SkTypeface.h"
36
+ #include " SkTypes.h"
37
+ #include " SkUtils.h"
38
+ #include " platform/fonts/FontDescription.h"
39
+ #include " platform/fonts/GlyphPage.h"
40
+ #include " platform/fonts/VDMXParser.h"
41
+ #include " platform/geometry/FloatRect.h"
33
42
#include " wtf/MathExtras.h"
43
+ #include " wtf/unicode/Unicode.h"
44
+ #include < unicode/normlzr.h>
34
45
35
46
namespace blink {
36
47
37
48
const float smallCapsFontSizeMultiplier = 0 .7f ;
38
49
const float emphasisMarkFontSizeMultiplier = 0 .5f ;
39
50
51
+ #if OS(LINUX) || OS(ANDROID)
52
+ // This is the largest VDMX table which we'll try to load and parse.
53
+ static const size_t maxVDMXTableSize = 1024 * 1024 ; // 1 MB
54
+ #endif
55
+
40
56
SimpleFontData::SimpleFontData (const FontPlatformData& platformData, PassRefPtr<CustomFontData> customData, bool isTextOrientationFallback)
41
57
: m_maxCharWidth(-1 )
42
58
, m_avgCharWidth(-1 )
@@ -52,7 +68,6 @@ SimpleFontData::SimpleFontData(const FontPlatformData& platformData, PassRefPtr<
52
68
{
53
69
platformInit ();
54
70
platformGlyphInit ();
55
- platformCharWidthInit ();
56
71
#if ENABLE(OPENTYPE_VERTICAL)
57
72
if (platformData.orientation () == Vertical && !isTextOrientationFallback) {
58
73
m_verticalData = platformData.verticalData ();
@@ -76,6 +91,142 @@ SimpleFontData::SimpleFontData(PassRefPtr<CustomFontData> customData, float font
76
91
m_customFontData->initializeFontData (this , fontSize);
77
92
}
78
93
94
+ void SimpleFontData::platformInit ()
95
+ {
96
+ if (!m_platformData.size ()) {
97
+ m_fontMetrics.reset ();
98
+ m_avgCharWidth = 0 ;
99
+ m_maxCharWidth = 0 ;
100
+ return ;
101
+ }
102
+
103
+ SkPaint paint;
104
+ SkPaint::FontMetrics metrics;
105
+
106
+ m_platformData.setupPaint (&paint);
107
+ paint.getFontMetrics (&metrics);
108
+ SkTypeface* face = paint.getTypeface ();
109
+ ASSERT (face);
110
+
111
+ int vdmxAscent = 0 , vdmxDescent = 0 ;
112
+ bool isVDMXValid = false ;
113
+
114
+ #if OS(LINUX) || OS(ANDROID)
115
+ // Manually digging up VDMX metrics is only applicable when bytecode hinting using FreeType.
116
+ // With GDI, the metrics will already have taken this into account (as needed).
117
+ // With DirectWrite or CoreText, no bytecode hinting is ever done.
118
+ // This code should be pushed into FreeType (hinted font metrics).
119
+ static const uint32_t vdmxTag = SkSetFourByteTag (' V' , ' D' , ' M' , ' X' );
120
+ int pixelSize = m_platformData.size () + 0.5 ;
121
+ if (!paint.isAutohinted ()
122
+ && (paint.getHinting () == SkPaint::kFull_Hinting
123
+ || paint.getHinting () == SkPaint::kNormal_Hinting ))
124
+ {
125
+ size_t vdmxSize = face->getTableSize (vdmxTag);
126
+ if (vdmxSize && vdmxSize < maxVDMXTableSize) {
127
+ uint8_t * vdmxTable = (uint8_t *) fastMalloc (vdmxSize);
128
+ if (vdmxTable
129
+ && face->getTableData (vdmxTag, 0 , vdmxSize, vdmxTable) == vdmxSize
130
+ && parseVDMX (&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize))
131
+ isVDMXValid = true ;
132
+ fastFree (vdmxTable);
133
+ }
134
+ }
135
+ #endif
136
+
137
+ float ascent;
138
+ float descent;
139
+
140
+ // Beware those who step here: This code is designed to match Win32 font
141
+ // metrics *exactly* (except the adjustment of ascent/descent on Linux/Android).
142
+ if (isVDMXValid) {
143
+ ascent = vdmxAscent;
144
+ descent = -vdmxDescent;
145
+ } else {
146
+ ascent = SkScalarRoundToInt (-metrics.fAscent );
147
+ descent = SkScalarRoundToInt (metrics.fDescent );
148
+ #if OS(LINUX) || OS(ANDROID)
149
+ // When subpixel positioning is enabled, if the descent is rounded down, the descent part
150
+ // of the glyph may be truncated when displayed in a 'overflow: hidden' container.
151
+ // To avoid that, borrow 1 unit from the ascent when possible.
152
+ // FIXME: This can be removed if sub-pixel ascent/descent is supported.
153
+ if (platformData ().fontRenderStyle ().useSubpixelPositioning && descent < SkScalarToFloat (metrics.fDescent ) && ascent >= 1 ) {
154
+ ++descent;
155
+ --ascent;
156
+ }
157
+ #endif
158
+ }
159
+
160
+ m_fontMetrics.setAscent (ascent);
161
+ m_fontMetrics.setDescent (descent);
162
+
163
+ float xHeight;
164
+ if (metrics.fXHeight ) {
165
+ xHeight = metrics.fXHeight ;
166
+ m_fontMetrics.setXHeight (xHeight);
167
+ } else {
168
+ xHeight = ascent * 0.56 ; // Best guess from Windows font metrics.
169
+ m_fontMetrics.setXHeight (xHeight);
170
+ m_fontMetrics.setHasXHeight (false );
171
+ }
172
+
173
+ float lineGap = SkScalarToFloat (metrics.fLeading );
174
+ m_fontMetrics.setLineGap (lineGap);
175
+ m_fontMetrics.setLineSpacing (lroundf (ascent) + lroundf (descent) + lroundf (lineGap));
176
+
177
+ if (platformData ().orientation () == Vertical && !isTextOrientationFallback ()) {
178
+ static const uint32_t vheaTag = SkSetFourByteTag (' v' , ' h' , ' e' , ' a' );
179
+ static const uint32_t vorgTag = SkSetFourByteTag (' V' , ' O' , ' R' , ' G' );
180
+ size_t vheaSize = face->getTableSize (vheaTag);
181
+ size_t vorgSize = face->getTableSize (vorgTag);
182
+ if ((vheaSize > 0 ) || (vorgSize > 0 ))
183
+ m_hasVerticalGlyphs = true ;
184
+ }
185
+
186
+ // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is
187
+ // calculated for us, but we need to calculate m_maxCharWidth and
188
+ // m_avgCharWidth in order for text entry widgets to be sized correctly.
189
+ #if OS(WIN)
190
+ m_maxCharWidth = SkScalarRoundToInt (metrics.fMaxCharWidth );
191
+
192
+ // Older version of the DirectWrite API doesn't implement support for max
193
+ // char width. Fall back on a multiple of the ascent. This is entirely
194
+ // arbitrary but comes pretty close to the expected value in most cases.
195
+ if (m_maxCharWidth < 1 )
196
+ m_maxCharWidth = ascent * 2 ;
197
+ #else
198
+ // FIXME: This seems incorrect and should probably use fMaxCharWidth as
199
+ // the code path above.
200
+ SkScalar xRange = metrics.fXMax - metrics.fXMin ;
201
+ m_maxCharWidth = SkScalarRoundToInt (xRange * SkScalarRoundToInt (m_platformData.size ()));
202
+ #endif
203
+
204
+ if (metrics.fAvgCharWidth ) {
205
+ m_avgCharWidth = SkScalarRoundToInt (metrics.fAvgCharWidth );
206
+ } else {
207
+ m_avgCharWidth = xHeight;
208
+
209
+ GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild (this , 0 )->page ();
210
+
211
+ if (glyphPageZero) {
212
+ static const UChar32 xChar = ' x' ;
213
+ const Glyph xGlyph = glyphPageZero->glyphForCharacter (xChar);
214
+
215
+ if (xGlyph) {
216
+ // In widthForGlyph(), xGlyph will be compared with
217
+ // m_zeroWidthSpaceGlyph, which isn't initialized yet here.
218
+ // Initialize it with zero to make sure widthForGlyph() returns
219
+ // the right width.
220
+ m_zeroWidthSpaceGlyph = 0 ;
221
+ m_avgCharWidth = widthForGlyph (xGlyph);
222
+ }
223
+ }
224
+ }
225
+
226
+ if (int unitsPerEm = face->getUnitsPerEm ())
227
+ m_fontMetrics.setUnitsPerEm (unitsPerEm);
228
+ }
229
+
79
230
void SimpleFontData::platformGlyphInit ()
80
231
{
81
232
GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild (this , 0 )->page ();
@@ -118,9 +269,6 @@ void SimpleFontData::platformGlyphInit()
118
269
119
270
SimpleFontData::~SimpleFontData ()
120
271
{
121
- if (!isSVGFont ())
122
- platformDestroy ();
123
-
124
272
if (isCustomFont ())
125
273
GlyphPageTreeNode::pruneTreeCustomFontData (this );
126
274
else
@@ -227,4 +375,115 @@ PassRefPtr<SimpleFontData> SimpleFontData::createScaledFontData(const FontDescri
227
375
return platformCreateScaledFontData (fontDescription, scaleFactor);
228
376
}
229
377
378
+
379
+
380
+ PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData (const FontDescription& fontDescription, float scaleFactor) const
381
+ {
382
+ const float scaledSize = lroundf (fontDescription.computedSize () * scaleFactor);
383
+ return SimpleFontData::create (FontPlatformData (m_platformData, scaledSize), isCustomFont () ? CustomFontData::create () : nullptr );
384
+ }
385
+
386
+ void SimpleFontData::determinePitch ()
387
+ {
388
+ m_treatAsFixedPitch = platformData ().isFixedPitch ();
389
+ }
390
+
391
+ static inline void getSkiaBoundsForGlyph (SkPaint& paint, Glyph glyph, SkRect& bounds)
392
+ {
393
+ paint.setTextEncoding (SkPaint::kGlyphID_TextEncoding );
394
+
395
+ SkPath path;
396
+ paint.getTextPath (&glyph, sizeof (glyph), 0 , 0 , &path);
397
+ bounds = path.getBounds ();
398
+
399
+ if (!paint.isSubpixelText ()) {
400
+ SkIRect ir;
401
+ bounds.round (&ir);
402
+ bounds.set (ir);
403
+ }
404
+ }
405
+
406
+ FloatRect SimpleFontData::platformBoundsForGlyph (Glyph glyph) const
407
+ {
408
+ if (!m_platformData.size ())
409
+ return FloatRect ();
410
+
411
+ SkASSERT (sizeof (glyph) == 2 ); // compile-time assert
412
+
413
+ SkPaint paint;
414
+ m_platformData.setupPaint (&paint);
415
+
416
+ SkRect bounds;
417
+ getSkiaBoundsForGlyph (paint, glyph, bounds);
418
+ return FloatRect (bounds);
419
+ }
420
+
421
+ float SimpleFontData::platformWidthForGlyph (Glyph glyph) const
422
+ {
423
+ if (!m_platformData.size ())
424
+ return 0 ;
425
+
426
+ SkASSERT (sizeof (glyph) == 2 ); // compile-time assert
427
+
428
+ SkPaint paint;
429
+
430
+ m_platformData.setupPaint (&paint);
431
+
432
+ paint.setTextEncoding (SkPaint::kGlyphID_TextEncoding );
433
+ SkScalar width = paint.measureText (&glyph, 2 );
434
+ if (!paint.isSubpixelText ())
435
+ width = SkScalarRoundToInt (width);
436
+ return SkScalarToFloat (width);
437
+ }
438
+
439
+ bool SimpleFontData::canRenderCombiningCharacterSequence (const UChar* characters, size_t length) const
440
+ {
441
+ if (!m_combiningCharacterSequenceSupport)
442
+ m_combiningCharacterSequenceSupport = adoptPtr (new HashMap<String, bool >);
443
+
444
+ WTF::HashMap<String, bool >::AddResult addResult = m_combiningCharacterSequenceSupport->add (String (characters, length), false );
445
+ if (!addResult.isNewEntry )
446
+ return addResult.storedValue ->value ;
447
+
448
+ UErrorCode error = U_ZERO_ERROR;
449
+ Vector<UChar, 4 > normalizedCharacters (length);
450
+ int32_t normalizedLength = unorm_normalize (characters, length, UNORM_NFC, UNORM_UNICODE_3_2, &normalizedCharacters[0 ], length, &error);
451
+ // Can't render if we have an error or no composition occurred.
452
+ if (U_FAILURE (error) || (static_cast <size_t >(normalizedLength) == length))
453
+ return false ;
454
+
455
+ SkPaint paint;
456
+ m_platformData.setupPaint (&paint);
457
+ paint.setTextEncoding (SkPaint::kUTF16_TextEncoding );
458
+ if (paint.textToGlyphs (&normalizedCharacters[0 ], normalizedLength * 2 , 0 )) {
459
+ addResult.storedValue ->value = true ;
460
+ return true ;
461
+ }
462
+ return false ;
463
+ }
464
+
465
+ bool SimpleFontData::fillGlyphPage (GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const
466
+ {
467
+ if (SkUTF16_IsHighSurrogate (buffer[bufferLength-1 ])) {
468
+ SkDebugf (" %s last char is high-surrogate" , __FUNCTION__);
469
+ return false ;
470
+ }
471
+
472
+ SkAutoSTMalloc<GlyphPage::size, uint16_t > glyphStorage (length);
473
+
474
+ uint16_t * glyphs = glyphStorage.get ();
475
+ SkTypeface* typeface = platformData ().typeface ();
476
+ typeface->charsToGlyphs (buffer, SkTypeface::kUTF16_Encoding , glyphs, length);
477
+
478
+ bool haveGlyphs = false ;
479
+ for (unsigned i = 0 ; i < length; i++) {
480
+ if (glyphs[i]) {
481
+ pageToFill->setGlyphDataForIndex (offset + i, glyphs[i], this );
482
+ haveGlyphs = true ;
483
+ }
484
+ }
485
+
486
+ return haveGlyphs;
487
+ }
488
+
230
489
} // namespace blink
0 commit comments