Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

Side by Side Diff: ui/gfx/harfbuzz_font_skia.cc

Issue 891183003: Extract the Skia implementation of HarfBuzz font to its own file (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/harfbuzz_font_skia.h ('k') | ui/gfx/render_text_harfbuzz.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gfx/harfbuzz_font_skia.h"
6
7 #include <limits>
8 #include <map>
9
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "third_party/skia/include/core/SkPaint.h"
13 #include "third_party/skia/include/core/SkTypeface.h"
14 #include "ui/gfx/render_text.h"
15
16 namespace gfx {
17
18 namespace {
19
20 class HarfBuzzFace;
21
22 // Maps from code points to glyph indices in a font.
23 typedef std::map<uint32_t, uint16_t> GlyphCache;
24
25 typedef std::pair<HarfBuzzFace, GlyphCache> FaceCache;
26
27 // Font data provider for HarfBuzz using Skia. Copied from Blink.
28 // TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375
29 struct FontData {
30 FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
31
32 SkPaint paint_;
33 GlyphCache* glyph_cache_;
34 };
35
36 // Deletes the object at the given pointer after casting it to the given type.
37 template<typename Type>
38 void DeleteByType(void* data) {
39 Type* typed_data = reinterpret_cast<Type*>(data);
40 delete typed_data;
41 }
42
43 template<typename Type>
44 void DeleteArrayByType(void* data) {
45 Type* typed_data = reinterpret_cast<Type*>(data);
46 delete[] typed_data;
47 }
48
49 // Outputs the |width| and |extents| of the glyph with index |codepoint| in
50 // |paint|'s font.
51 void GetGlyphWidthAndExtents(SkPaint* paint,
52 hb_codepoint_t codepoint,
53 hb_position_t* width,
54 hb_glyph_extents_t* extents) {
55 DCHECK_LE(codepoint, std::numeric_limits<uint16_t>::max());
56 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
57
58 SkScalar sk_width;
59 SkRect sk_bounds;
60 uint16_t glyph = static_cast<uint16_t>(codepoint);
61
62 paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds);
63 if (width)
64 *width = SkScalarToFixed(sk_width);
65 if (extents) {
66 // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be
67 // y-grows-up.
68 extents->x_bearing = SkScalarToFixed(sk_bounds.fLeft);
69 extents->y_bearing = SkScalarToFixed(-sk_bounds.fTop);
70 extents->width = SkScalarToFixed(sk_bounds.width());
71 extents->height = SkScalarToFixed(-sk_bounds.height());
72 }
73 }
74
75 // Writes the |glyph| index for the given |unicode| code point. Returns whether
76 // the glyph exists, i.e. it is not a missing glyph.
77 hb_bool_t GetGlyph(hb_font_t* font,
78 void* data,
79 hb_codepoint_t unicode,
80 hb_codepoint_t variation_selector,
81 hb_codepoint_t* glyph,
82 void* user_data) {
83 FontData* font_data = reinterpret_cast<FontData*>(data);
84 GlyphCache* cache = font_data->glyph_cache_;
85
86 bool exists = cache->count(unicode) != 0;
87 if (!exists) {
88 SkPaint* paint = &font_data->paint_;
89 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
90 paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]);
91 }
92 *glyph = (*cache)[unicode];
93 return !!*glyph;
94 }
95
96 // Returns the horizontal advance value of the |glyph|.
97 hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font,
98 void* data,
99 hb_codepoint_t glyph,
100 void* user_data) {
101 FontData* font_data = reinterpret_cast<FontData*>(data);
102 hb_position_t advance = 0;
103
104 GetGlyphWidthAndExtents(&font_data->paint_, glyph, &advance, 0);
105 return advance;
106 }
107
108 hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font,
109 void* data,
110 hb_codepoint_t glyph,
111 hb_position_t* x,
112 hb_position_t* y,
113 void* user_data) {
114 // Just return true, like the HarfBuzz-FreeType implementation.
115 return true;
116 }
117
118 hb_position_t GetGlyphKerning(FontData* font_data,
119 hb_codepoint_t first_glyph,
120 hb_codepoint_t second_glyph) {
121 SkTypeface* typeface = font_data->paint_.getTypeface();
122 const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph),
123 static_cast<uint16_t>(second_glyph) };
124 int32_t kerning_adjustments[1] = { 0 };
125
126 if (!typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments))
127 return 0;
128
129 SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
130 SkScalar size = font_data->paint_.getTextSize();
131 return SkScalarToFixed(
132 SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm));
133 }
134
135 hb_position_t GetGlyphHorizontalKerning(hb_font_t* font,
136 void* data,
137 hb_codepoint_t left_glyph,
138 hb_codepoint_t right_glyph,
139 void* user_data) {
140 FontData* font_data = reinterpret_cast<FontData*>(data);
141 if (font_data->paint_.isVerticalText()) {
142 // We don't support cross-stream kerning.
143 return 0;
144 }
145
146 return GetGlyphKerning(font_data, left_glyph, right_glyph);
147 }
148
149 hb_position_t GetGlyphVerticalKerning(hb_font_t* font,
150 void* data,
151 hb_codepoint_t top_glyph,
152 hb_codepoint_t bottom_glyph,
153 void* user_data) {
154 FontData* font_data = reinterpret_cast<FontData*>(data);
155 if (!font_data->paint_.isVerticalText()) {
156 // We don't support cross-stream kerning.
157 return 0;
158 }
159
160 return GetGlyphKerning(font_data, top_glyph, bottom_glyph);
161 }
162
163 // Writes the |extents| of |glyph|.
164 hb_bool_t GetGlyphExtents(hb_font_t* font,
165 void* data,
166 hb_codepoint_t glyph,
167 hb_glyph_extents_t* extents,
168 void* user_data) {
169 FontData* font_data = reinterpret_cast<FontData*>(data);
170
171 GetGlyphWidthAndExtents(&font_data->paint_, glyph, 0, extents);
172 return true;
173 }
174
175 class FontFuncs {
176 public:
177 FontFuncs() : font_funcs_(hb_font_funcs_create()) {
178 hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0);
179 hb_font_funcs_set_glyph_h_advance_func(
180 font_funcs_, GetGlyphHorizontalAdvance, 0, 0);
181 hb_font_funcs_set_glyph_h_kerning_func(
182 font_funcs_, GetGlyphHorizontalKerning, 0, 0);
183 hb_font_funcs_set_glyph_h_origin_func(
184 font_funcs_, GetGlyphHorizontalOrigin, 0, 0);
185 hb_font_funcs_set_glyph_v_kerning_func(
186 font_funcs_, GetGlyphVerticalKerning, 0, 0);
187 hb_font_funcs_set_glyph_extents_func(
188 font_funcs_, GetGlyphExtents, 0, 0);
189 hb_font_funcs_make_immutable(font_funcs_);
190 }
191
192 ~FontFuncs() {
193 hb_font_funcs_destroy(font_funcs_);
194 }
195
196 hb_font_funcs_t* get() { return font_funcs_; }
197
198 private:
199 hb_font_funcs_t* font_funcs_;
200
201 DISALLOW_COPY_AND_ASSIGN(FontFuncs);
202 };
203
204 base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER;
205
206 // Returns the raw data of the font table |tag|.
207 hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) {
208 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data);
209
210 const size_t table_size = typeface->getTableSize(tag);
211 if (!table_size)
212 return 0;
213
214 scoped_ptr<char[]> buffer(new char[table_size]);
215 if (!buffer)
216 return 0;
217 size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer.get());
218 if (table_size != actual_size)
219 return 0;
220
221 char* buffer_raw = buffer.release();
222 return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE,
223 buffer_raw, DeleteArrayByType<char>);
224 }
225
226 void UnrefSkTypeface(void* data) {
227 SkTypeface* skia_face = reinterpret_cast<SkTypeface*>(data);
228 SkSafeUnref(skia_face);
229 }
230
231 // Wrapper class for a HarfBuzz face created from a given Skia face.
232 class HarfBuzzFace {
233 public:
234 HarfBuzzFace() : face_(NULL) {}
235
236 ~HarfBuzzFace() {
237 if (face_)
238 hb_face_destroy(face_);
239 }
240
241 void Init(SkTypeface* skia_face) {
242 SkSafeRef(skia_face);
243 face_ = hb_face_create_for_tables(GetFontTable, skia_face, UnrefSkTypeface);
244 DCHECK(face_);
245 }
246
247 hb_face_t* get() {
248 return face_;
249 }
250
251 private:
252 hb_face_t* face_;
253 };
254
255 } // namespace
256
257 // Creates a HarfBuzz font from the given Skia face and text size.
258 hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face,
259 SkScalar text_size,
260 const FontRenderParams& params,
261 bool background_is_transparent) {
262 // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache?
263 static std::map<SkFontID, FaceCache> face_caches;
264
265 FaceCache* face_cache = &face_caches[skia_face->uniqueID()];
266 if (face_cache->first.get() == NULL)
267 face_cache->first.Init(skia_face);
268
269 hb_font_t* harfbuzz_font = hb_font_create(face_cache->first.get());
270 const int scale = SkScalarToFixed(text_size);
271 hb_font_set_scale(harfbuzz_font, scale, scale);
272 FontData* hb_font_data = new FontData(&face_cache->second);
273 hb_font_data->paint_.setTypeface(skia_face);
274 hb_font_data->paint_.setTextSize(text_size);
275 // TODO(ckocagil): Do we need to update these params later?
276 internal::ApplyRenderParams(params, background_is_transparent,
277 &hb_font_data->paint_);
278 hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data,
279 DeleteByType<FontData>);
280 hb_font_make_immutable(harfbuzz_font);
281 return harfbuzz_font;
282 }
283
284 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/harfbuzz_font_skia.h ('k') | ui/gfx/render_text_harfbuzz.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698