| 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
|
|
|