Index: ui/gfx/render_text_harfbuzz.cc |
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc |
index 82580b3961f5d475e71b407b70839cc35b8cc6be..ddc9d6f7b5f0d290a57d861deb7adf77d6a5d1dd 100644 |
--- a/ui/gfx/render_text_harfbuzz.cc |
+++ b/ui/gfx/render_text_harfbuzz.cc |
@@ -5,12 +5,10 @@ |
#include "ui/gfx/render_text_harfbuzz.h" |
#include <limits> |
-#include <map> |
#include "base/i18n/bidi_line_iterator.h" |
#include "base/i18n/break_iterator.h" |
#include "base/i18n/char_iterator.h" |
-#include "base/lazy_instance.h" |
#include "base/profiler/scoped_tracker.h" |
#include "third_party/harfbuzz-ng/src/hb.h" |
#include "third_party/icu/source/common/unicode/ubidi.h" |
@@ -19,6 +17,7 @@ |
#include "ui/gfx/canvas.h" |
#include "ui/gfx/font_fallback.h" |
#include "ui/gfx/font_render_params.h" |
+#include "ui/gfx/harfbuzz_font_skia.h" |
#include "ui/gfx/utf16_indexing.h" |
#if defined(OS_WIN) |
@@ -40,270 +39,6 @@ const size_t kMaxTextLength = 10000; |
// character to belong to more scripts. |
const size_t kMaxScripts = 5; |
-// Maps from code points to glyph indices in a font. |
-typedef std::map<uint32_t, uint16_t> GlyphCache; |
- |
-// Font data provider for HarfBuzz using Skia. Copied from Blink. |
-// TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375 |
-struct FontData { |
- FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {} |
- |
- SkPaint paint_; |
- GlyphCache* glyph_cache_; |
-}; |
- |
-hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) { |
- return SkScalarToFixed(value); |
-} |
- |
-// Deletes the object at the given pointer after casting it to the given type. |
-template<typename Type> |
-void DeleteByType(void* data) { |
- Type* typed_data = reinterpret_cast<Type*>(data); |
- delete typed_data; |
-} |
- |
-template<typename Type> |
-void DeleteArrayByType(void* data) { |
- Type* typed_data = reinterpret_cast<Type*>(data); |
- delete[] typed_data; |
-} |
- |
-// Outputs the |width| and |extents| of the glyph with index |codepoint| in |
-// |paint|'s font. |
-void GetGlyphWidthAndExtents(SkPaint* paint, |
- hb_codepoint_t codepoint, |
- hb_position_t* width, |
- hb_glyph_extents_t* extents) { |
- DCHECK_LE(codepoint, std::numeric_limits<uint16>::max()); |
- paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
- |
- SkScalar sk_width; |
- SkRect sk_bounds; |
- uint16_t glyph = static_cast<uint16_t>(codepoint); |
- |
- paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds); |
- if (width) |
- *width = SkiaScalarToHarfBuzzPosition(sk_width); |
- if (extents) { |
- // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be |
- // y-grows-up. |
- extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft); |
- extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop); |
- extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width()); |
- extents->height = SkiaScalarToHarfBuzzPosition(-sk_bounds.height()); |
- } |
-} |
- |
-// Writes the |glyph| index for the given |unicode| code point. Returns whether |
-// the glyph exists, i.e. it is not a missing glyph. |
-hb_bool_t GetGlyph(hb_font_t* font, |
- void* data, |
- hb_codepoint_t unicode, |
- hb_codepoint_t variation_selector, |
- hb_codepoint_t* glyph, |
- void* user_data) { |
- FontData* font_data = reinterpret_cast<FontData*>(data); |
- GlyphCache* cache = font_data->glyph_cache_; |
- |
- bool exists = cache->count(unicode) != 0; |
- if (!exists) { |
- SkPaint* paint = &font_data->paint_; |
- paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); |
- paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]); |
- } |
- *glyph = (*cache)[unicode]; |
- return !!*glyph; |
-} |
- |
-// Returns the horizontal advance value of the |glyph|. |
-hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font, |
- void* data, |
- hb_codepoint_t glyph, |
- void* user_data) { |
- FontData* font_data = reinterpret_cast<FontData*>(data); |
- hb_position_t advance = 0; |
- |
- GetGlyphWidthAndExtents(&font_data->paint_, glyph, &advance, 0); |
- return advance; |
-} |
- |
-hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font, |
- void* data, |
- hb_codepoint_t glyph, |
- hb_position_t* x, |
- hb_position_t* y, |
- void* user_data) { |
- // Just return true, like the HarfBuzz-FreeType implementation. |
- return true; |
-} |
- |
-hb_position_t GetGlyphKerning(FontData* font_data, |
- hb_codepoint_t first_glyph, |
- hb_codepoint_t second_glyph) { |
- SkTypeface* typeface = font_data->paint_.getTypeface(); |
- const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph), |
- static_cast<uint16_t>(second_glyph) }; |
- int32_t kerning_adjustments[1] = { 0 }; |
- |
- if (!typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments)) |
- return 0; |
- |
- SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm()); |
- SkScalar size = font_data->paint_.getTextSize(); |
- return SkiaScalarToHarfBuzzPosition( |
- SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm)); |
-} |
- |
-hb_position_t GetGlyphHorizontalKerning(hb_font_t* font, |
- void* data, |
- hb_codepoint_t left_glyph, |
- hb_codepoint_t right_glyph, |
- void* user_data) { |
- FontData* font_data = reinterpret_cast<FontData*>(data); |
- if (font_data->paint_.isVerticalText()) { |
- // We don't support cross-stream kerning. |
- return 0; |
- } |
- |
- return GetGlyphKerning(font_data, left_glyph, right_glyph); |
-} |
- |
-hb_position_t GetGlyphVerticalKerning(hb_font_t* font, |
- void* data, |
- hb_codepoint_t top_glyph, |
- hb_codepoint_t bottom_glyph, |
- void* user_data) { |
- FontData* font_data = reinterpret_cast<FontData*>(data); |
- if (!font_data->paint_.isVerticalText()) { |
- // We don't support cross-stream kerning. |
- return 0; |
- } |
- |
- return GetGlyphKerning(font_data, top_glyph, bottom_glyph); |
-} |
- |
-// Writes the |extents| of |glyph|. |
-hb_bool_t GetGlyphExtents(hb_font_t* font, |
- void* data, |
- hb_codepoint_t glyph, |
- hb_glyph_extents_t* extents, |
- void* user_data) { |
- FontData* font_data = reinterpret_cast<FontData*>(data); |
- |
- GetGlyphWidthAndExtents(&font_data->paint_, glyph, 0, extents); |
- return true; |
-} |
- |
-class FontFuncs { |
- public: |
- FontFuncs() : font_funcs_(hb_font_funcs_create()) { |
- hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0); |
- hb_font_funcs_set_glyph_h_advance_func( |
- font_funcs_, GetGlyphHorizontalAdvance, 0, 0); |
- hb_font_funcs_set_glyph_h_kerning_func( |
- font_funcs_, GetGlyphHorizontalKerning, 0, 0); |
- hb_font_funcs_set_glyph_h_origin_func( |
- font_funcs_, GetGlyphHorizontalOrigin, 0, 0); |
- hb_font_funcs_set_glyph_v_kerning_func( |
- font_funcs_, GetGlyphVerticalKerning, 0, 0); |
- hb_font_funcs_set_glyph_extents_func( |
- font_funcs_, GetGlyphExtents, 0, 0); |
- hb_font_funcs_make_immutable(font_funcs_); |
- } |
- |
- ~FontFuncs() { |
- hb_font_funcs_destroy(font_funcs_); |
- } |
- |
- hb_font_funcs_t* get() { return font_funcs_; } |
- |
- private: |
- hb_font_funcs_t* font_funcs_; |
- |
- DISALLOW_COPY_AND_ASSIGN(FontFuncs); |
-}; |
- |
-base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER; |
- |
-// Returns the raw data of the font table |tag|. |
-hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) { |
- SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data); |
- |
- const size_t table_size = typeface->getTableSize(tag); |
- if (!table_size) |
- return 0; |
- |
- scoped_ptr<char[]> buffer(new char[table_size]); |
- if (!buffer) |
- return 0; |
- size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer.get()); |
- if (table_size != actual_size) |
- return 0; |
- |
- char* buffer_raw = buffer.release(); |
- return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE, |
- buffer_raw, DeleteArrayByType<char>); |
-} |
- |
-void UnrefSkTypeface(void* data) { |
- SkTypeface* skia_face = reinterpret_cast<SkTypeface*>(data); |
- SkSafeUnref(skia_face); |
-} |
- |
-// Wrapper class for a HarfBuzz face created from a given Skia face. |
-class HarfBuzzFace { |
- public: |
- HarfBuzzFace() : face_(NULL) {} |
- |
- ~HarfBuzzFace() { |
- if (face_) |
- hb_face_destroy(face_); |
- } |
- |
- void Init(SkTypeface* skia_face) { |
- SkSafeRef(skia_face); |
- face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface); |
- DCHECK(face_); |
- } |
- |
- hb_face_t* get() { |
- return face_; |
- } |
- |
- private: |
- hb_face_t* face_; |
-}; |
- |
-// Creates a HarfBuzz font from the given Skia face and text size. |
-hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, |
- SkScalar text_size, |
- const FontRenderParams& params, |
- bool background_is_transparent) { |
- typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache; |
- |
- // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache? |
- static std::map<SkFontID, FaceCache> face_caches; |
- |
- FaceCache* face_cache = &face_caches[skia_face->uniqueID()]; |
- if (face_cache->first.get() == NULL) |
- face_cache->first.Init(skia_face); |
- |
- hb_font_t* harfbuzz_font = hb_font_create(face_cache->first.get()); |
- const int scale = SkScalarToFixed(text_size); |
- hb_font_set_scale(harfbuzz_font, scale, scale); |
- FontData* hb_font_data = new FontData(&face_cache->second); |
- hb_font_data->paint_.setTypeface(skia_face); |
- hb_font_data->paint_.setTextSize(text_size); |
- // TODO(ckocagil): Do we need to update these params later? |
- internal::ApplyRenderParams(params, background_is_transparent, |
- &hb_font_data->paint_); |
- hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data, |
- DeleteByType<FontData>); |
- hb_font_make_immutable(harfbuzz_font); |
- return harfbuzz_font; |
-} |
- |
// Returns true if characters of |block_code| may trigger font fallback. |
// Dingbats and emoticons can be rendered through the color emoji font file, |
// therefore it needs to be trigerred as fallbacks. See crbug.com/448909 |