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

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