OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 Google Inc. All rights reserved. | 2 * Copyright (c) 2012 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 13 matching lines...) Expand all Loading... |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "config.h" | 31 #include "config.h" |
32 #include "platform/fonts/harfbuzz/HarfBuzzFace.h" | 32 #include "platform/fonts/harfbuzz/HarfBuzzFace.h" |
33 | 33 |
34 #include "platform/fonts/FontPlatformData.h" | |
35 #include "hb-ot.h" | 34 #include "hb-ot.h" |
36 #include "hb.h" | 35 #include "hb.h" |
| 36 #if OS(MACOSX) |
| 37 #include "hb-coretext.h" |
| 38 #endif |
| 39 #include "SkPaint.h" |
| 40 #include "SkPath.h" |
| 41 #include "SkPoint.h" |
| 42 #include "SkRect.h" |
| 43 #include "SkTypeface.h" |
| 44 #include "SkUtils.h" |
| 45 #include "platform/fonts/FontPlatformData.h" |
| 46 #include "platform/fonts/SimpleFontData.h" |
| 47 #include "platform/fonts/harfbuzz/HarfBuzzShaper.h" |
| 48 #include "wtf/HashMap.h" |
37 | 49 |
38 namespace blink { | 50 namespace blink { |
39 | 51 |
40 const hb_tag_t HarfBuzzFace::vertTag = HB_TAG('v', 'e', 'r', 't'); | 52 const hb_tag_t HarfBuzzFace::vertTag = HB_TAG('v', 'e', 'r', 't'); |
41 const hb_tag_t HarfBuzzFace::vrt2Tag = HB_TAG('v', 'r', 't', '2'); | 53 const hb_tag_t HarfBuzzFace::vrt2Tag = HB_TAG('v', 'r', 't', '2'); |
42 | 54 |
43 // Though we have FontCache class, which provides the cache mechanism for | 55 // Though we have FontCache class, which provides the cache mechanism for |
44 // WebKit's font objects, we also need additional caching layer for HarfBuzz | 56 // WebKit's font objects, we also need additional caching layer for HarfBuzz |
45 // to reduce the memory consumption because hb_face_t should be associated with | 57 // to reduce the memory consumption because hb_face_t should be associated with |
46 // underling font data (e.g. CTFontRef, FTFace). | 58 // underling font data (e.g. CTFontRef, FTFace). |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 return HB_SCRIPT_INVALID; | 133 return HB_SCRIPT_INVALID; |
122 } | 134 } |
123 | 135 |
124 void HarfBuzzFace::setScriptForVerticalGlyphSubstitution(hb_buffer_t* buffer) | 136 void HarfBuzzFace::setScriptForVerticalGlyphSubstitution(hb_buffer_t* buffer) |
125 { | 137 { |
126 if (m_scriptForVerticalText == HB_SCRIPT_INVALID) | 138 if (m_scriptForVerticalText == HB_SCRIPT_INVALID) |
127 m_scriptForVerticalText = findScriptForVerticalGlyphSubstitution(m_face)
; | 139 m_scriptForVerticalText = findScriptForVerticalGlyphSubstitution(m_face)
; |
128 hb_buffer_set_script(buffer, m_scriptForVerticalText); | 140 hb_buffer_set_script(buffer, m_scriptForVerticalText); |
129 } | 141 } |
130 | 142 |
| 143 struct HarfBuzzFontData { |
| 144 HarfBuzzFontData(WTF::HashMap<uint32_t, uint16_t>* glyphCacheForFaceCacheEnt
ry) |
| 145 : m_glyphCacheForFaceCacheEntry(glyphCacheForFaceCacheEntry) |
| 146 { } |
| 147 SkPaint m_paint; |
| 148 WTF::HashMap<uint32_t, uint16_t>* m_glyphCacheForFaceCacheEntry; |
| 149 }; |
| 150 |
| 151 static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) |
| 152 { |
| 153 return SkScalarToFixed(value); |
| 154 } |
| 155 |
| 156 static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint
, hb_position_t* width, hb_glyph_extents_t* extents) |
| 157 { |
| 158 ASSERT(codepoint <= 0xFFFF); |
| 159 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 160 |
| 161 SkScalar skWidth; |
| 162 SkRect skBounds; |
| 163 uint16_t glyph = codepoint; |
| 164 |
| 165 paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); |
| 166 if (width) |
| 167 *width = SkiaScalarToHarfBuzzPosition(skWidth); |
| 168 if (extents) { |
| 169 // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to
be y-grows-up. |
| 170 extents->x_bearing = SkiaScalarToHarfBuzzPosition(skBounds.fLeft); |
| 171 extents->y_bearing = SkiaScalarToHarfBuzzPosition(-skBounds.fTop); |
| 172 extents->width = SkiaScalarToHarfBuzzPosition(skBounds.width()); |
| 173 extents->height = SkiaScalarToHarfBuzzPosition(-skBounds.height()); |
| 174 } |
| 175 } |
| 176 |
| 177 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) |
| 178 { |
| 179 // Variation selectors not supported. |
| 180 if (variationSelector) |
| 181 return false; |
| 182 |
| 183 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; |
| 184 |
| 185 WTF::HashMap<uint32_t, uint16_t>::AddResult result = hbFontData->m_glyphCach
eForFaceCacheEntry->add(unicode, 0); |
| 186 if (result.isNewEntry) { |
| 187 SkPaint* paint = &hbFontData->m_paint; |
| 188 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| 189 uint16_t glyph16; |
| 190 paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &glyph16); |
| 191 result.storedValue->value = glyph16; |
| 192 *glyph = glyph16; |
| 193 } |
| 194 *glyph = result.storedValue->value; |
| 195 return !!*glyph; |
| 196 } |
| 197 |
| 198 static hb_position_t harfBuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void*
fontData, hb_codepoint_t glyph, void* userData) |
| 199 { |
| 200 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; |
| 201 hb_position_t advance = 0; |
| 202 |
| 203 SkiaGetGlyphWidthAndExtents(&hbFontData->m_paint, glyph, &advance, 0); |
| 204 return advance; |
| 205 } |
| 206 |
| 207 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) |
| 208 { |
| 209 // Just return true, following the way that HarfBuzz-FreeType |
| 210 // implementation does. |
| 211 return true; |
| 212 } |
| 213 |
| 214 static hb_position_t harfBuzzGetGlyphHorizontalKerning(hb_font_t*, void* fontDat
a, hb_codepoint_t leftGlyph, hb_codepoint_t rightGlyph, void*) |
| 215 { |
| 216 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; |
| 217 if (hbFontData->m_paint.isVerticalText()) { |
| 218 // We don't support cross-stream kerning |
| 219 return 0; |
| 220 } |
| 221 |
| 222 SkTypeface* typeface = hbFontData->m_paint.getTypeface(); |
| 223 |
| 224 const uint16_t glyphs[2] = { static_cast<uint16_t>(leftGlyph), static_cast<u
int16_t>(rightGlyph) }; |
| 225 int32_t kerningAdjustments[1] = { 0 }; |
| 226 |
| 227 if (typeface->getKerningPairAdjustments(glyphs, 2, kerningAdjustments)) { |
| 228 SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); |
| 229 SkScalar size = hbFontData->m_paint.getTextSize(); |
| 230 return SkiaScalarToHarfBuzzPosition(SkScalarMulDiv(SkIntToScalar(kerning
Adjustments[0]), size, upm)); |
| 231 } |
| 232 |
| 233 return 0; |
| 234 } |
| 235 |
| 236 |
| 237 static hb_bool_t harfBuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_c
odepoint_t glyph, hb_glyph_extents_t* extents, void* userData) |
| 238 { |
| 239 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData)
; |
| 240 |
| 241 SkiaGetGlyphWidthAndExtents(&hbFontData->m_paint, glyph, 0, extents); |
| 242 return true; |
| 243 } |
| 244 |
| 245 static hb_font_funcs_t* harfBuzzSkiaGetFontFuncs() |
| 246 { |
| 247 static hb_font_funcs_t* harfBuzzSkiaFontFuncs = 0; |
| 248 |
| 249 // We don't set callback functions which we can't support. |
| 250 // HarfBuzz will use the fallback implementation if they aren't set. |
| 251 if (!harfBuzzSkiaFontFuncs) { |
| 252 harfBuzzSkiaFontFuncs = hb_font_funcs_create(); |
| 253 hb_font_funcs_set_glyph_func(harfBuzzSkiaFontFuncs, harfBuzzGetGlyph, 0,
0); |
| 254 hb_font_funcs_set_glyph_h_advance_func(harfBuzzSkiaFontFuncs, harfBuzzGe
tGlyphHorizontalAdvance, 0, 0); |
| 255 hb_font_funcs_set_glyph_h_kerning_func(harfBuzzSkiaFontFuncs, harfBuzzGe
tGlyphHorizontalKerning, 0, 0); |
| 256 hb_font_funcs_set_glyph_h_origin_func(harfBuzzSkiaFontFuncs, harfBuzzGet
GlyphHorizontalOrigin, 0, 0); |
| 257 hb_font_funcs_set_glyph_extents_func(harfBuzzSkiaFontFuncs, harfBuzzGetG
lyphExtents, 0, 0); |
| 258 hb_font_funcs_make_immutable(harfBuzzSkiaFontFuncs); |
| 259 } |
| 260 return harfBuzzSkiaFontFuncs; |
| 261 } |
| 262 |
| 263 #if !OS(MACOSX) |
| 264 static hb_blob_t* harfBuzzSkiaGetTable(hb_face_t* face, hb_tag_t tag, void* user
Data) |
| 265 { |
| 266 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); |
| 267 |
| 268 const size_t tableSize = typeface->getTableSize(tag); |
| 269 if (!tableSize) { |
| 270 return 0; |
| 271 } |
| 272 |
| 273 char* buffer = reinterpret_cast<char*>(fastMalloc(tableSize)); |
| 274 if (!buffer) |
| 275 return 0; |
| 276 size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer); |
| 277 if (tableSize != actualSize) { |
| 278 fastFree(buffer); |
| 279 return 0; |
| 280 } |
| 281 |
| 282 return hb_blob_create(const_cast<char*>(buffer), tableSize, HB_MEMORY_MODE_W
RITABLE, buffer, fastFree); |
| 283 } |
| 284 #endif |
| 285 |
| 286 static void destroyHarfBuzzFontData(void* userData) |
| 287 { |
| 288 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(userData)
; |
| 289 delete hbFontData; |
| 290 } |
| 291 |
| 292 hb_face_t* HarfBuzzFace::createFace() |
| 293 { |
| 294 #if OS(MACOSX) |
| 295 hb_face_t* face = hb_coretext_face_create(m_platformData->cgFont()); |
| 296 #else |
| 297 hb_face_t* face = hb_face_create_for_tables(harfBuzzSkiaGetTable, m_platform
Data->typeface(), 0); |
| 298 #endif |
| 299 ASSERT(face); |
| 300 return face; |
| 301 } |
| 302 |
| 303 hb_font_t* HarfBuzzFace::createFont() |
| 304 { |
| 305 HarfBuzzFontData* hbFontData = new HarfBuzzFontData(m_glyphCacheForFaceCache
Entry); |
| 306 m_platformData->setupPaint(&hbFontData->m_paint); |
| 307 hb_font_t* font = hb_font_create(m_face); |
| 308 hb_font_set_funcs(font, harfBuzzSkiaGetFontFuncs(), hbFontData, destroyHarfB
uzzFontData); |
| 309 float size = m_platformData->size(); |
| 310 int scale = SkiaScalarToHarfBuzzPosition(size); |
| 311 hb_font_set_scale(font, scale, scale); |
| 312 hb_font_make_immutable(font); |
| 313 return font; |
| 314 } |
| 315 |
131 } // namespace blink | 316 } // namespace blink |
OLD | NEW |