OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 Google Inc. All rights reserved. | |
3 * Copyright (c) 2014 BlackBerry Limited. All rights reserved. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are | |
7 * met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above | |
12 * copyright notice, this list of conditions and the following disclaimer | |
13 * in the documentation and/or other materials provided with the | |
14 * distribution. | |
15 * * Neither the name of Google Inc. nor the names of its | |
16 * contributors may be used to endorse or promote products derived from | |
17 * this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 */ | |
31 | |
32 #include "config.h" | |
33 #include "platform/fonts/harfbuzz/HarfBuzzFace.h" | |
34 | |
35 #include "SkPaint.h" | |
36 #include "SkPath.h" | |
37 #include "SkPoint.h" | |
38 #include "SkRect.h" | |
39 #include "SkTypeface.h" | |
40 #include "SkUtils.h" | |
41 #include "platform/fonts/FontPlatformData.h" | |
42 #include "platform/fonts/SimpleFontData.h" | |
43 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" | |
44 | |
45 #include "hb.h" | |
46 #include "wtf/HashMap.h" | |
47 | |
48 namespace blink { | |
49 | |
50 // Our implementation of the callbacks which HarfBuzz requires by using Skia | |
51 // calls. See the HarfBuzz source for references about what these callbacks do. | |
52 | |
53 struct HarfBuzzFontData { | |
54 HarfBuzzFontData(WTF::HashMap<uint32_t, uint16_t>* glyphCacheForFaceCacheEnt
ry) | |
55 : m_glyphCacheForFaceCacheEntry(glyphCacheForFaceCacheEntry) | |
56 { } | |
57 SkPaint m_paint; | |
58 WTF::HashMap<uint32_t, uint16_t>* m_glyphCacheForFaceCacheEntry; | |
59 }; | |
60 | |
61 static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) | |
62 { | |
63 return SkScalarToFixed(value); | |
64 } | |
65 | |
66 static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint
, hb_position_t* width, hb_glyph_extents_t* extents) | |
67 { | |
68 ASSERT(codepoint <= 0xFFFF); | |
69 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); | |
70 | |
71 SkScalar skWidth; | |
72 SkRect skBounds; | |
73 uint16_t glyph = codepoint; | |
74 | |
75 paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); | |
76 if (width) | |
77 *width = SkiaScalarToHarfBuzzPosition(skWidth); | |
78 if (extents) { | |
79 // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to
be y-grows-up. | |
80 extents->x_bearing = SkiaScalarToHarfBuzzPosition(skBounds.fLeft); | |
81 extents->y_bearing = SkiaScalarToHarfBuzzPosition(-skBounds.fTop); | |
82 extents->width = SkiaScalarToHarfBuzzPosition(skBounds.width()); | |
83 extents->height = SkiaScalarToHarfBuzzPosition(-skBounds.height()); | |
84 } | |
85 } | |
86 | |
87 static hb_bool_t harfBuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoin
t_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* user
Data) | |
88 { | |
89 // Variation selectors not supported. | |
90 if (variationSelector) | |
91 return false; | |
92 | |
93 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; | |
94 | |
95 WTF::HashMap<uint32_t, uint16_t>::AddResult result = hbFontData->m_glyphCach
eForFaceCacheEntry->add(unicode, 0); | |
96 if (result.isNewEntry) { | |
97 SkPaint* paint = &hbFontData->m_paint; | |
98 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); | |
99 uint16_t glyph16; | |
100 paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &glyph16); | |
101 result.storedValue->value = glyph16; | |
102 *glyph = glyph16; | |
103 } | |
104 *glyph = result.storedValue->value; | |
105 return !!*glyph; | |
106 } | |
107 | |
108 static hb_position_t harfBuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void*
fontData, hb_codepoint_t glyph, void* userData) | |
109 { | |
110 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; | |
111 hb_position_t advance = 0; | |
112 | |
113 SkiaGetGlyphWidthAndExtents(&hbFontData->m_paint, glyph, &advance, 0); | |
114 return advance; | |
115 } | |
116 | |
117 static hb_bool_t harfBuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontD
ata, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData) | |
118 { | |
119 // Just return true, following the way that HarfBuzz-FreeType | |
120 // implementation does. | |
121 return true; | |
122 } | |
123 | |
124 static hb_position_t harfBuzzGetGlyphHorizontalKerning(hb_font_t*, void* fontDat
a, hb_codepoint_t leftGlyph, hb_codepoint_t rightGlyph, void*) | |
125 { | |
126 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; | |
127 if (hbFontData->m_paint.isVerticalText()) { | |
128 // We don't support cross-stream kerning | |
129 return 0; | |
130 } | |
131 | |
132 SkTypeface* typeface = hbFontData->m_paint.getTypeface(); | |
133 | |
134 const uint16_t glyphs[2] = { static_cast<uint16_t>(leftGlyph), static_cast<u
int16_t>(rightGlyph) }; | |
135 int32_t kerningAdjustments[1] = { 0 }; | |
136 | |
137 if (typeface->getKerningPairAdjustments(glyphs, 2, kerningAdjustments)) { | |
138 SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); | |
139 SkScalar size = hbFontData->m_paint.getTextSize(); | |
140 return SkiaScalarToHarfBuzzPosition(SkScalarMulDiv(SkIntToScalar(kerning
Adjustments[0]), size, upm)); | |
141 } | |
142 | |
143 return 0; | |
144 } | |
145 | |
146 static hb_position_t harfBuzzGetGlyphVerticalKerning(hb_font_t*, void* fontData,
hb_codepoint_t topGlyph, hb_codepoint_t bottomGlyph, void*) | |
147 { | |
148 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; | |
149 if (!hbFontData->m_paint.isVerticalText()) { | |
150 // We don't support cross-stream kerning | |
151 return 0; | |
152 } | |
153 | |
154 SkTypeface* typeface = hbFontData->m_paint.getTypeface(); | |
155 | |
156 const uint16_t glyphs[2] = { static_cast<uint16_t>(topGlyph), static_cast<ui
nt16_t>(bottomGlyph) }; | |
157 int32_t kerningAdjustments[1] = { 0 }; | |
158 | |
159 if (typeface->getKerningPairAdjustments(glyphs, 2, kerningAdjustments)) { | |
160 SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); | |
161 SkScalar size = hbFontData->m_paint.getTextSize(); | |
162 return SkiaScalarToHarfBuzzPosition(SkScalarMulDiv(SkIntToScalar(kerning
Adjustments[0]), size, upm)); | |
163 } | |
164 | |
165 return 0; | |
166 } | |
167 | |
168 static hb_bool_t harfBuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_c
odepoint_t glyph, hb_glyph_extents_t* extents, void* userData) | |
169 { | |
170 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; | |
171 | |
172 SkiaGetGlyphWidthAndExtents(&hbFontData->m_paint, glyph, 0, extents); | |
173 return true; | |
174 } | |
175 | |
176 static hb_font_funcs_t* harfBuzzSkiaGetFontFuncs() | |
177 { | |
178 static hb_font_funcs_t* harfBuzzSkiaFontFuncs = 0; | |
179 | |
180 // We don't set callback functions which we can't support. | |
181 // HarfBuzz will use the fallback implementation if they aren't set. | |
182 if (!harfBuzzSkiaFontFuncs) { | |
183 harfBuzzSkiaFontFuncs = hb_font_funcs_create(); | |
184 hb_font_funcs_set_glyph_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyph, 0,
0); | |
185 hb_font_funcs_set_glyph_h_advance_func(harfBuzzSkiaFontFuncs, harfBuzzGe
tGlyphHorizontalAdvance, 0, 0); | |
186 hb_font_funcs_set_glyph_h_kerning_func(harfBuzzSkiaFontFuncs, harfBuzzGe
tGlyphHorizontalKerning, 0, 0); | |
187 hb_font_funcs_set_glyph_h_origin_func(harfBuzzSkiaFontFuncs, harfBuzzGet
GlyphHorizontalOrigin, 0, 0); | |
188 hb_font_funcs_set_glyph_v_kerning_func(harfBuzzSkiaFontFuncs, harfBuzzGe
tGlyphVerticalKerning, 0, 0); | |
189 hb_font_funcs_set_glyph_extents_func(harfBuzzSkiaFontFuncs, harfBuzzGetG
lyphExtents, 0, 0); | |
190 hb_font_funcs_make_immutable(harfBuzzSkiaFontFuncs); | |
191 } | |
192 return harfBuzzSkiaFontFuncs; | |
193 } | |
194 | |
195 static hb_blob_t* harfBuzzSkiaGetTable(hb_face_t* face, hb_tag_t tag, void* user
Data) | |
196 { | |
197 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); | |
198 | |
199 const size_t tableSize = typeface->getTableSize(tag); | |
200 if (!tableSize) | |
201 return 0; | |
202 | |
203 char* buffer = reinterpret_cast<char*>(fastMalloc(tableSize)); | |
204 if (!buffer) | |
205 return 0; | |
206 size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer); | |
207 if (tableSize != actualSize) { | |
208 fastFree(buffer); | |
209 return 0; | |
210 } | |
211 | |
212 return hb_blob_create(const_cast<char*>(buffer), tableSize, HB_MEMORY_MODE_W
RITABLE, buffer, fastFree); | |
213 } | |
214 | |
215 static void destroyHarfBuzzFontData(void* userData) | |
216 { | |
217 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(userData)
; | |
218 delete hbFontData; | |
219 } | |
220 | |
221 hb_face_t* HarfBuzzFace::createFace() | |
222 { | |
223 hb_face_t* face = hb_face_create_for_tables(harfBuzzSkiaGetTable, m_platform
Data->typeface(), 0); | |
224 ASSERT(face); | |
225 return face; | |
226 } | |
227 | |
228 hb_font_t* HarfBuzzFace::createFont() | |
229 { | |
230 HarfBuzzFontData* hbFontData = new HarfBuzzFontData(m_glyphCacheForFaceCache
Entry); | |
231 m_platformData->setupPaint(&hbFontData->m_paint); | |
232 hb_font_t* font = hb_font_create(m_face); | |
233 hb_font_set_funcs(font, harfBuzzSkiaGetFontFuncs(), hbFontData, destroyHarfB
uzzFontData); | |
234 float size = m_platformData->size(); | |
235 int scale = SkiaScalarToHarfBuzzPosition(size); | |
236 hb_font_set_scale(font, scale, scale); | |
237 hb_font_make_immutable(font); | |
238 return font; | |
239 } | |
240 | |
241 } // namespace blink | |
OLD | NEW |