1/* 2 * Copyright (c) 2012 Google Inc. All rights reserved. 3 * Copyright (c) 2012 Intel Corporation 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 "HarfBuzzFace.h" 34 35#include "FontPlatformData.h" 36#include "GlyphBuffer.h" 37#include "HarfBuzzShaper.h" 38#include "SimpleFontData.h" 39#include "TextEncoding.h" 40#include <cairo-ft.h> 41#include <cairo.h> 42#include <ft2build.h> 43#include FT_FREETYPE_H 44#include FT_TRUETYPE_TABLES_H 45#include <hb.h> 46#include <wtf/text/CString.h> 47#include <wtf/text/StringView.h> 48 49namespace WebCore { 50 51struct HarfBuzzFontData { 52 HarfBuzzFontData(WTF::HashMap<uint32_t, uint16_t>* glyphCacheForFaceCacheEntry, cairo_scaled_font_t* cairoScaledFont) 53 : m_glyphCacheForFaceCacheEntry(glyphCacheForFaceCacheEntry) 54 , m_cairoScaledFont(cairoScaledFont) 55 { } 56 WTF::HashMap<uint32_t, uint16_t>* m_glyphCacheForFaceCacheEntry; 57 cairo_scaled_font_t* m_cairoScaledFont; 58}; 59 60class CairoFtFaceLocker { 61public: 62 CairoFtFaceLocker(cairo_scaled_font_t* cairoScaledFont) : m_scaledFont(cairoScaledFont) { }; 63 FT_Face lock() 64 { 65 return cairo_ft_scaled_font_lock_face(m_scaledFont); 66 }; 67 ~CairoFtFaceLocker() 68 { 69 cairo_ft_scaled_font_unlock_face(m_scaledFont); 70 } 71private: 72 cairo_scaled_font_t* m_scaledFont; 73}; 74 75static hb_position_t floatToHarfBuzzPosition(float value) 76{ 77 return static_cast<hb_position_t>(value * (1 << 16)); 78} 79 80static hb_position_t doubleToHarfBuzzPosition(double value) 81{ 82 return static_cast<hb_position_t>(value * (1 << 16)); 83} 84 85static void CairoGetGlyphWidthAndExtents(cairo_scaled_font_t* scaledFont, hb_codepoint_t codepoint, hb_position_t* advance, hb_glyph_extents_t* extents) 86{ 87 cairo_text_extents_t glyphExtents; 88 cairo_glyph_t glyph; 89 glyph.index = codepoint; 90 glyph.x = 0; 91 glyph.y = 0; 92 cairo_scaled_font_glyph_extents(scaledFont, &glyph, 1, &glyphExtents); 93 94 bool hasVerticalGlyphs = glyphExtents.y_advance; 95 if (advance) 96 *advance = doubleToHarfBuzzPosition(hasVerticalGlyphs ? -glyphExtents.y_advance : glyphExtents.x_advance); 97 98 if (extents) { 99 extents->x_bearing = doubleToHarfBuzzPosition(glyphExtents.x_bearing); 100 extents->y_bearing = doubleToHarfBuzzPosition(hasVerticalGlyphs ? -glyphExtents.y_bearing : glyphExtents.y_bearing); 101 extents->width = doubleToHarfBuzzPosition(hasVerticalGlyphs ? -glyphExtents.height : glyphExtents.width); 102 extents->height = doubleToHarfBuzzPosition(hasVerticalGlyphs ? glyphExtents.width : glyphExtents.height); 103 } 104} 105 106static hb_bool_t harfBuzzGetGlyph(hb_font_t*, void* fontData, hb_codepoint_t unicode, hb_codepoint_t, hb_codepoint_t* glyph, void*) 107{ 108 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 109 cairo_scaled_font_t* scaledFont = hbFontData->m_cairoScaledFont; 110 ASSERT(scaledFont); 111 112 WTF::HashMap<uint32_t, uint16_t>::AddResult result = hbFontData->m_glyphCacheForFaceCacheEntry->add(unicode, 0); 113 if (result.isNewEntry) { 114 cairo_glyph_t* glyphs = 0; 115 int numGlyphs = 0; 116 CString utf8Codepoint = UTF8Encoding().encode(StringView(reinterpret_cast<UChar*>(&unicode), 1), QuestionMarksForUnencodables); 117 if (cairo_scaled_font_text_to_glyphs(scaledFont, 0, 0, utf8Codepoint.data(), utf8Codepoint.length(), &glyphs, &numGlyphs, 0, 0, 0) != CAIRO_STATUS_SUCCESS) 118 return false; 119 if (!numGlyphs) 120 return false; 121 result.iterator->value = glyphs[0].index; 122 cairo_glyph_free(glyphs); 123 } 124 *glyph = result.iterator->value; 125 return !!*glyph; 126} 127 128static hb_position_t harfBuzzGetGlyphHorizontalAdvance(hb_font_t*, void* fontData, hb_codepoint_t glyph, void*) 129{ 130 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 131 cairo_scaled_font_t* scaledFont = hbFontData->m_cairoScaledFont; 132 ASSERT(scaledFont); 133 134 hb_position_t advance = 0; 135 CairoGetGlyphWidthAndExtents(scaledFont, glyph, &advance, 0); 136 return advance; 137} 138 139static hb_bool_t harfBuzzGetGlyphHorizontalOrigin(hb_font_t*, void*, hb_codepoint_t, hb_position_t*, hb_position_t*, void*) 140{ 141 // Just return true, following the way that Harfbuzz-FreeType 142 // implementation does. 143 return true; 144} 145 146static hb_bool_t harfBuzzGetGlyphExtents(hb_font_t*, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void*) 147{ 148 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 149 cairo_scaled_font_t* scaledFont = hbFontData->m_cairoScaledFont; 150 ASSERT(scaledFont); 151 152 CairoGetGlyphWidthAndExtents(scaledFont, glyph, 0, extents); 153 return true; 154} 155 156static hb_font_funcs_t* harfBuzzCairoTextGetFontFuncs() 157{ 158 static hb_font_funcs_t* harfBuzzCairoFontFuncs = 0; 159 160 // We don't set callback functions which we can't support. 161 // Harfbuzz will use the fallback implementation if they aren't set. 162 if (!harfBuzzCairoFontFuncs) { 163 harfBuzzCairoFontFuncs = hb_font_funcs_create(); 164 hb_font_funcs_set_glyph_func(harfBuzzCairoFontFuncs, harfBuzzGetGlyph, 0, 0); 165 hb_font_funcs_set_glyph_h_advance_func(harfBuzzCairoFontFuncs, harfBuzzGetGlyphHorizontalAdvance, 0, 0); 166 hb_font_funcs_set_glyph_h_origin_func(harfBuzzCairoFontFuncs, harfBuzzGetGlyphHorizontalOrigin, 0, 0); 167 hb_font_funcs_set_glyph_extents_func(harfBuzzCairoFontFuncs, harfBuzzGetGlyphExtents, 0, 0); 168 hb_font_funcs_make_immutable(harfBuzzCairoFontFuncs); 169 } 170 return harfBuzzCairoFontFuncs; 171} 172 173static hb_blob_t* harfBuzzCairoGetTable(hb_face_t*, hb_tag_t tag, void* userData) 174{ 175 cairo_scaled_font_t* scaledFont = reinterpret_cast<cairo_scaled_font_t*>(userData); 176 if (!scaledFont) 177 return 0; 178 179 CairoFtFaceLocker cairoFtFaceLocker(scaledFont); 180 FT_Face ftFont = cairoFtFaceLocker.lock(); 181 if (!ftFont) 182 return 0; 183 184 FT_ULong tableSize = 0; 185 FT_Error error = FT_Load_Sfnt_Table(ftFont, tag, 0, 0, &tableSize); 186 if (error) 187 return 0; 188 189 FT_Byte* buffer = reinterpret_cast<FT_Byte*>(fastMalloc(tableSize)); 190 if (!buffer) 191 return 0; 192 FT_ULong expectedTableSize = tableSize; 193 error = FT_Load_Sfnt_Table(ftFont, tag, 0, buffer, &tableSize); 194 if (error || tableSize != expectedTableSize) { 195 fastFree(buffer); 196 return 0; 197 } 198 199 return hb_blob_create(reinterpret_cast<const char*>(buffer), tableSize, HB_MEMORY_MODE_WRITABLE, buffer, fastFree); 200} 201 202static void destroyHarfBuzzFontData(void* userData) 203{ 204 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(userData); 205 delete hbFontData; 206} 207 208hb_face_t* HarfBuzzFace::createFace() 209{ 210 hb_face_t* face = hb_face_create_for_tables(harfBuzzCairoGetTable, m_platformData->scaledFont(), 0); 211 ASSERT(face); 212 return face; 213} 214 215hb_font_t* HarfBuzzFace::createFont() 216{ 217 hb_font_t* font = hb_font_create(m_face); 218 HarfBuzzFontData* hbFontData = new HarfBuzzFontData(m_glyphCacheForFaceCacheEntry, m_platformData->scaledFont()); 219 hb_font_set_funcs(font, harfBuzzCairoTextGetFontFuncs(), hbFontData, destroyHarfBuzzFontData); 220 const float size = m_platformData->size(); 221 if (floorf(size) == size) 222 hb_font_set_ppem(font, size, size); 223 int scale = floatToHarfBuzzPosition(size); 224 hb_font_set_scale(font, scale, scale); 225 hb_font_make_immutable(font); 226 return font; 227} 228 229GlyphBufferAdvance HarfBuzzShaper::createGlyphBufferAdvance(float width, float height) 230{ 231 return GlyphBufferAdvance(width, height); 232} 233 234} // namespace WebCore 235