OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "build/build_config.h" |
| 6 |
5 #include "webkit/glue/plugins/pepper_font.h" | 7 #include "webkit/glue/plugins/pepper_font.h" |
6 | 8 |
| 9 #if defined(OS_LINUX) |
| 10 #include <unistd.h> |
| 11 #endif |
| 12 |
7 #include "base/logging.h" | 13 #include "base/logging.h" |
8 #include "base/utf_string_conversions.h" | |
9 #include "third_party/ppapi/c/pp_rect.h" | |
10 #include "third_party/ppapi/c/ppb_font.h" | 14 #include "third_party/ppapi/c/ppb_font.h" |
11 #include "third_party/WebKit/WebKit/chromium/public/WebFont.h" | |
12 #include "third_party/WebKit/WebKit/chromium/public/WebFontDescription.h" | |
13 #include "third_party/WebKit/WebKit/chromium/public/WebRect.h" | |
14 #include "third_party/WebKit/WebKit/chromium/public/WebFloatPoint.h" | |
15 #include "third_party/WebKit/WebKit/chromium/public/WebFloatRect.h" | |
16 #include "third_party/WebKit/WebKit/chromium/public/WebTextRun.h" | |
17 #include "webkit/glue/plugins/pepper_image_data.h" | |
18 #include "webkit/glue/plugins/pepper_plugin_module.h" | 15 #include "webkit/glue/plugins/pepper_plugin_module.h" |
19 #include "webkit/glue/plugins/pepper_string.h" | |
20 #include "webkit/glue/plugins/pepper_var.h" | |
21 #include "webkit/glue/webkit_glue.h" | 16 #include "webkit/glue/webkit_glue.h" |
22 | 17 |
23 using WebKit::WebFloatPoint; | |
24 using WebKit::WebFloatRect; | |
25 using WebKit::WebFont; | |
26 using WebKit::WebFontDescription; | |
27 using WebKit::WebRect; | |
28 using WebKit::WebTextRun; | |
29 | |
30 namespace pepper { | 18 namespace pepper { |
31 | 19 |
32 namespace { | 20 namespace { |
33 | 21 |
34 bool IsPPFontDescriptionValid(const PP_FontDescription& desc) { | 22 PP_Resource MatchFontWithFallback(PP_Module module_id, |
35 // Check validity of UTF-8. | 23 const PP_FontDescription* description) { |
36 if (desc.face.type != PP_VARTYPE_STRING && desc.face.type != PP_VARTYPE_VOID) | 24 #if defined(OS_LINUX) |
37 return false; | |
38 | |
39 if (static_cast<int>(desc.family) < PP_FONTFAMILY_DEFAULT || | |
40 static_cast<int>(desc.family) > PP_FONTFAMILY_MONOSPACE) | |
41 return false; | |
42 if (static_cast<int>(desc.weight) < PP_FONTWEIGHT_100 || | |
43 static_cast<int>(desc.weight) > PP_FONTWEIGHT_900) | |
44 return false; | |
45 | |
46 return true; | |
47 } | |
48 | |
49 // The PP_* version lacks "None", so is just one value shifted from the | |
50 // WebFontDescription version. These values are checked in | |
51 // PPFontDescToWebFontDesc to make sure the conversion is correct. This is a | |
52 // macro so it can also be used in the COMPILE_ASSERTS. | |
53 #define PP_FONTFAMILY_TO_WEB_FONTFAMILY(f) \ | |
54 static_cast<WebFontDescription::GenericFamily>(f + 1) | |
55 | |
56 // Assumes the given PP_FontDescription has been validated. | |
57 WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription& font) { | |
58 // Verify that the enums match so we can just static cast. | |
59 COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) == | |
60 static_cast<int>(PP_FONTWEIGHT_100), | |
61 FontWeight100); | |
62 COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) == | |
63 static_cast<int>(PP_FONTWEIGHT_900), | |
64 FontWeight900); | |
65 COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard == | |
66 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_DEFAULT), | |
67 StandardFamily); | |
68 COMPILE_ASSERT(WebFontDescription::GenericFamilySerif == | |
69 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SERIF), | |
70 SerifFamily); | |
71 COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif == | |
72 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SANSSERIF), | |
73 SansSerifFamily); | |
74 COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace == | |
75 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_MONOSPACE), | |
76 MonospaceFamily); | |
77 | |
78 WebFontDescription result; | |
79 String* face_name = GetString(font.face); | |
80 if (face_name) | |
81 result.family = UTF8ToUTF16(face_name->value()); | |
82 result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family); | |
83 result.size = static_cast<float>(font.size); | |
84 result.italic = font.italic; | |
85 result.smallCaps = font.small_caps; | |
86 result.weight = static_cast<WebFontDescription::Weight>(font.weight); | |
87 result.letterSpacing = static_cast<short>(font.letter_spacing); | |
88 result.wordSpacing = static_cast<short>(font.word_spacing); | |
89 return result; | |
90 } | |
91 | |
92 // Converts the given PP_TextRun to a WebTextRun, returning true on success. | |
93 // False means the input was invalid. | |
94 bool PPTextRunToWebTextRun(const PP_TextRun* run, WebTextRun* output) { | |
95 String* text_string = GetString(run->text); | |
96 if (!text_string) | |
97 return false; | |
98 *output = WebTextRun(UTF8ToUTF16(text_string->value()), | |
99 run->rtl, run->override_direction); | |
100 return true; | |
101 } | |
102 | |
103 PP_Resource Create(PP_Module module_id, | |
104 const PP_FontDescription* description) { | |
105 PluginModule* module = PluginModule::FromPPModule(module_id); | 25 PluginModule* module = PluginModule::FromPPModule(module_id); |
106 if (!module) | 26 if (!module) |
107 return 0; | 27 return 0; |
108 | 28 |
109 if (!IsPPFontDescriptionValid(*description)) | 29 int fd = webkit_glue::MatchFontWithFallback(description->face, |
| 30 description->weight >= 700, |
| 31 description->italic, |
| 32 description->charset); |
| 33 if (fd == -1) |
110 return 0; | 34 return 0; |
111 | 35 |
112 scoped_refptr<Font> font(new Font(module, *description)); | 36 scoped_refptr<Font> font(new Font(module, fd)); |
| 37 |
113 return font->GetReference(); | 38 return font->GetReference(); |
| 39 #else |
| 40 // For trusted pepper plugins, this is only needed in Linux since font loading |
| 41 // on Windows and Mac works through the renderer sandbox. |
| 42 return false; |
| 43 #endif |
114 } | 44 } |
115 | 45 |
116 bool IsFont(PP_Resource resource) { | 46 bool IsFont(PP_Resource resource) { |
117 return !!Resource::GetAs<Font>(resource).get(); | 47 return !!Resource::GetAs<Font>(resource); |
118 } | 48 } |
119 | 49 |
120 bool Describe(PP_Resource font_id, | 50 bool GetFontTable(PP_Resource font_id, |
121 PP_FontDescription* description, | 51 uint32_t table, |
122 PP_FontMetrics* metrics) { | 52 void* output, |
| 53 uint32_t* output_length) { |
123 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); | 54 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); |
124 if (!font.get()) | 55 if (!font.get()) |
125 return false; | 56 return false; |
126 return font->Describe(description, metrics); | |
127 } | |
128 | 57 |
129 bool DrawTextAt(PP_Resource font_id, | 58 return font->GetFontTable(table, output, output_length); |
130 PP_Resource image_data, | |
131 const PP_TextRun* text, | |
132 const PP_Point* position, | |
133 uint32_t color, | |
134 const PP_Rect* clip, | |
135 bool image_data_is_opaque) { | |
136 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); | |
137 if (!font.get()) | |
138 return false; | |
139 return font->DrawTextAt(image_data, text, position, color, clip, | |
140 image_data_is_opaque); | |
141 } | |
142 | |
143 int32_t MeasureText(PP_Resource font_id, const PP_TextRun* text) { | |
144 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); | |
145 if (!font.get()) | |
146 return -1; | |
147 return font->MeasureText(text); | |
148 } | |
149 | |
150 uint32_t CharacterOffsetForPixel(PP_Resource font_id, | |
151 const PP_TextRun* text, | |
152 int32_t pixel_position) { | |
153 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); | |
154 if (!font.get()) | |
155 return false; | |
156 return font->CharacterOffsetForPixel(text, pixel_position); | |
157 } | |
158 | |
159 int32_t PixelOffsetForCharacter(PP_Resource font_id, | |
160 const PP_TextRun* text, | |
161 uint32_t char_offset) { | |
162 scoped_refptr<Font> font(Resource::GetAs<Font>(font_id)); | |
163 if (!font.get()) | |
164 return false; | |
165 return font->PixelOffsetForCharacter(text, char_offset); | |
166 } | 59 } |
167 | 60 |
168 const PPB_Font ppb_font = { | 61 const PPB_Font ppb_font = { |
169 &Create, | 62 &MatchFontWithFallback, |
170 &IsFont, | 63 &IsFont, |
171 &Describe, | 64 &GetFontTable, |
172 &DrawTextAt, | |
173 &MeasureText, | |
174 &CharacterOffsetForPixel, | |
175 &PixelOffsetForCharacter | |
176 }; | 65 }; |
177 | 66 |
178 } // namespace | 67 } // namespace |
179 | 68 |
180 Font::Font(PluginModule* module, const PP_FontDescription& desc) | 69 Font::Font(PluginModule* module, int fd) |
181 : Resource(module) { | 70 : Resource(module), |
182 WebFontDescription web_font_desc = PPFontDescToWebFontDesc(desc); | 71 fd_(fd) { |
183 font_.reset(WebFont::create(web_font_desc)); | |
184 } | 72 } |
185 | 73 |
186 Font::~Font() { | 74 Font::~Font() { |
| 75 #if defined (OS_LINUX) |
| 76 close(fd_); |
| 77 #endif |
187 } | 78 } |
188 | 79 |
189 // static | 80 // static |
190 const PPB_Font* Font::GetInterface() { | 81 const PPB_Font* Font::GetInterface() { |
191 return &ppb_font; | 82 return &ppb_font; |
192 } | 83 } |
193 | 84 |
194 bool Font::Describe(PP_FontDescription* description, | 85 bool Font::GetFontTable(uint32_t table, |
195 PP_FontMetrics* metrics) { | 86 void* output, |
196 if (description->face.type != PP_VARTYPE_VOID) | 87 uint32_t* output_length) { |
197 return false; | 88 #if defined(OS_LINUX) |
198 | 89 size_t temp_size = static_cast<size_t>(*output_length); |
199 WebFontDescription web_desc = font_->fontDescription(); | 90 bool rv = webkit_glue::GetFontTable( |
200 | 91 fd_, table, static_cast<uint8_t*>(output), &temp_size); |
201 // While converting the other way in PPFontDescToWebFontDesc we validated | 92 *output_length = static_cast<uint32_t>(temp_size); |
202 // that the enums can be casted. | 93 return rv; |
203 description->face = StringToPPVar(UTF16ToUTF8(web_desc.family)); | 94 #else |
204 description->family = static_cast<PP_FontFamily>(web_desc.genericFamily); | 95 return false; |
205 description->size = static_cast<uint32_t>(web_desc.size); | 96 #endif |
206 description->weight = static_cast<PP_FontWeight>(web_desc.weight); | |
207 description->italic = web_desc.italic; | |
208 description->small_caps = web_desc.smallCaps; | |
209 | |
210 metrics->height = font_->height(); | |
211 metrics->ascent = font_->ascent(); | |
212 metrics->descent = font_->descent(); | |
213 metrics->line_spacing = font_->lineSpacing(); | |
214 metrics->x_height = static_cast<int32_t>(font_->xHeight()); | |
215 | |
216 return true; | |
217 } | |
218 | |
219 bool Font::DrawTextAt(PP_Resource image_data, | |
220 const PP_TextRun* text, | |
221 const PP_Point* position, | |
222 uint32_t color, | |
223 const PP_Rect* clip, | |
224 bool image_data_is_opaque) { | |
225 WebTextRun run; | |
226 if (!PPTextRunToWebTextRun(text, &run)) | |
227 return false; | |
228 | |
229 // Get and map the image data we're painting to. | |
230 scoped_refptr<ImageData> image_resource( | |
231 Resource::GetAs<ImageData>(image_data)); | |
232 if (!image_resource.get()) | |
233 return false; | |
234 ImageDataAutoMapper mapper(image_resource); | |
235 if (!mapper.is_valid()) | |
236 return false; | |
237 | |
238 // Convert position and clip. | |
239 WebFloatPoint web_position(static_cast<float>(position->x), | |
240 static_cast<float>(position->y)); | |
241 WebRect web_clip; | |
242 if (!clip) { | |
243 // Use entire canvas. | |
244 web_clip = WebRect(0, 0, image_resource->width(), image_resource->height()); | |
245 } else { | |
246 web_clip = WebRect(clip->point.x, clip->point.y, | |
247 clip->size.width, clip->size.height); | |
248 } | |
249 | |
250 font_->drawText(webkit_glue::ToWebCanvas(image_resource->mapped_canvas()), | |
251 run, web_position, color, web_clip, image_data_is_opaque); | |
252 return true; | |
253 } | |
254 | |
255 int32_t Font::MeasureText(const PP_TextRun* text) { | |
256 WebTextRun run; | |
257 if (!PPTextRunToWebTextRun(text, &run)) | |
258 return -1; | |
259 return font_->calculateWidth(run); | |
260 } | |
261 | |
262 uint32_t Font::CharacterOffsetForPixel(const PP_TextRun* text, | |
263 int32_t pixel_position) { | |
264 WebTextRun run; | |
265 if (!PPTextRunToWebTextRun(text, &run)) | |
266 return -1; | |
267 | |
268 return static_cast<uint32_t>(font_->offsetForPosition( | |
269 run, static_cast<float>(pixel_position))); | |
270 } | |
271 | |
272 int32_t Font::PixelOffsetForCharacter(const PP_TextRun* text, | |
273 uint32_t char_offset) { | |
274 WebTextRun run; | |
275 if (!PPTextRunToWebTextRun(text, &run)) | |
276 return -1; | |
277 if (char_offset >= run.text.length()) | |
278 return -1; | |
279 | |
280 WebFloatRect rect = font_->selectionRectForText( | |
281 run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset); | |
282 return static_cast<int>(rect.width); | |
283 } | 97 } |
284 | 98 |
285 } // namespace pepper | 99 } // namespace pepper |
OLD | NEW |