| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "ppapi/shared_impl/ppb_font_shared.h" | 5 #include "ppapi/shared_impl/private/ppb_font_shared.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" |
| 8 #include "base/string_util.h" |
| 9 #include "base/utf_string_conversions.h" |
| 7 #include "ppapi/c/dev/ppb_font_dev.h" | 10 #include "ppapi/c/dev/ppb_font_dev.h" |
| 11 #include "ppapi/shared_impl/ppapi_preferences.h" |
| 12 #include "ppapi/shared_impl/var.h" |
| 13 #include "ppapi/thunk/enter.h" |
| 14 #include "ppapi/thunk/ppb_image_data_api.h" |
| 15 #include "ppapi/thunk/thunk.h" |
| 16 #include "skia/ext/platform_canvas.h" |
| 17 #include "third_party/skia/include/core/SkRect.h" |
| 18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCanvas.h" |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoin
t.h" |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatRect
.h" |
| 21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" |
| 22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFont.h" |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFontDescription.h" |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextRun.h" |
| 25 |
| 26 using ppapi::StringVar; |
| 27 using ppapi::thunk::EnterResource; |
| 28 using ppapi::thunk::EnterResourceNoLock; |
| 29 using ppapi::thunk::PPB_ImageData_API; |
| 30 using ppapi::WebKitForwarding; |
| 31 using WebKit::WebFloatPoint; |
| 32 using WebKit::WebFloatRect; |
| 33 using WebKit::WebFont; |
| 34 using WebKit::WebFontDescription; |
| 35 using WebKit::WebRect; |
| 36 using WebKit::WebTextRun; |
| 37 using WebKit::WebCanvas; |
| 8 | 38 |
| 9 namespace ppapi { | 39 namespace ppapi { |
| 10 | 40 |
| 41 namespace { |
| 42 |
| 43 // Converts the given PP_TextRun to a TextRun, returning true on success. |
| 44 // False means the input was invalid. |
| 45 bool PPTextRunToTextRun(const PP_TextRun_Dev* run, |
| 46 WebKitForwarding::Font::TextRun* output) { |
| 47 StringVar* text_string = StringVar::FromPPVar(run->text); |
| 48 if (!text_string) |
| 49 return false; |
| 50 |
| 51 output->text = text_string->value(); |
| 52 output->rtl = run->rtl == PP_TRUE ? true : false; |
| 53 output->override_direction = |
| 54 run->override_direction == PP_TRUE ? true : false; |
| 55 return true; |
| 56 } |
| 57 |
| 58 // The PP_* version lacks "None", so is just one value shifted from the |
| 59 // WebFontDescription version. These values are checked in |
| 60 // PPFontDescToWebFontDesc to make sure the conversion is correct. This is a |
| 61 // macro so it can also be used in the COMPILE_ASSERTS. |
| 62 #define PP_FONTFAMILY_TO_WEB_FONTFAMILY(f) \ |
| 63 static_cast<WebFontDescription::GenericFamily>(f + 1) |
| 64 |
| 65 // Assumes the given PP_FontDescription has been validated. |
| 66 WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font, |
| 67 const std::string& face, |
| 68 const ::ppapi::Preferences& prefs) { |
| 69 // Verify that the enums match so we can just static cast. |
| 70 COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) == |
| 71 static_cast<int>(PP_FONTWEIGHT_100), |
| 72 FontWeight100); |
| 73 COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) == |
| 74 static_cast<int>(PP_FONTWEIGHT_900), |
| 75 FontWeight900); |
| 76 COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard == |
| 77 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_DEFAULT), |
| 78 StandardFamily); |
| 79 COMPILE_ASSERT(WebFontDescription::GenericFamilySerif == |
| 80 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SERIF), |
| 81 SerifFamily); |
| 82 COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif == |
| 83 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SANSSERIF), |
| 84 SansSerifFamily); |
| 85 COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace == |
| 86 PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_MONOSPACE), |
| 87 MonospaceFamily); |
| 88 |
| 89 WebFontDescription result; |
| 90 string16 resolved_family; |
| 91 if (face.empty()) { |
| 92 // Resolve the generic family. |
| 93 switch (font.family) { |
| 94 case PP_FONTFAMILY_SERIF: |
| 95 resolved_family = prefs.serif_font_family; |
| 96 break; |
| 97 case PP_FONTFAMILY_SANSSERIF: |
| 98 resolved_family = prefs.sans_serif_font_family; |
| 99 break; |
| 100 case PP_FONTFAMILY_MONOSPACE: |
| 101 resolved_family = prefs.fixed_font_family; |
| 102 break; |
| 103 case PP_FONTFAMILY_DEFAULT: |
| 104 default: |
| 105 resolved_family = prefs.standard_font_family; |
| 106 break; |
| 107 } |
| 108 } else { |
| 109 // Use the exact font. |
| 110 resolved_family = UTF8ToUTF16(face); |
| 111 } |
| 112 result.family = resolved_family; |
| 113 |
| 114 result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family); |
| 115 |
| 116 if (font.size == 0) { |
| 117 // Resolve the default font size, using the resolved family to see if |
| 118 // we should use the fixed or regular font size. It's difficult at this |
| 119 // level to detect if the requested font is fixed width, so we only apply |
| 120 // the alternate font size to the default fixed font family. |
| 121 if (StringToLowerASCII(resolved_family) == |
| 122 StringToLowerASCII(prefs.fixed_font_family)) |
| 123 result.size = static_cast<float>(prefs.default_fixed_font_size); |
| 124 else |
| 125 result.size = static_cast<float>(prefs.default_font_size); |
| 126 } else { |
| 127 // Use the exact size. |
| 128 result.size = static_cast<float>(font.size); |
| 129 } |
| 130 |
| 131 result.italic = font.italic != PP_FALSE; |
| 132 result.smallCaps = font.small_caps != PP_FALSE; |
| 133 result.weight = static_cast<WebFontDescription::Weight>(font.weight); |
| 134 result.letterSpacing = static_cast<short>(font.letter_spacing); |
| 135 result.wordSpacing = static_cast<short>(font.word_spacing); |
| 136 return result; |
| 137 } |
| 138 |
| 139 WebTextRun TextRunToWebTextRun(const WebKitForwarding::Font::TextRun& run) { |
| 140 return WebTextRun(UTF8ToUTF16(run.text), |
| 141 run.rtl != PP_FALSE, |
| 142 run.override_direction != PP_FALSE); |
| 143 } |
| 144 |
| 145 // FontImpl -------------------------------------------------------------------- |
| 146 |
| 147 class FontImpl : public WebKitForwarding::Font { |
| 148 public: |
| 149 FontImpl(const PP_FontDescription_Dev& desc, |
| 150 const std::string& desc_face, |
| 151 const ::ppapi::Preferences& prefs); |
| 152 virtual ~FontImpl(); |
| 153 |
| 154 virtual void Describe(PP_FontDescription_Dev* description, |
| 155 std::string* face, |
| 156 PP_FontMetrics_Dev* metrics, |
| 157 PP_Bool* result) OVERRIDE; |
| 158 virtual void DrawTextAt(const DrawTextParams& params) OVERRIDE; |
| 159 virtual void MeasureText(const TextRun& text, |
| 160 int32_t* result) OVERRIDE; |
| 161 virtual void CharacterOffsetForPixel(const TextRun& text, |
| 162 int32_t pixel_position, |
| 163 uint32_t* result) OVERRIDE; |
| 164 virtual void PixelOffsetForCharacter(const TextRun& text, |
| 165 uint32_t char_offset, |
| 166 int32_t* result) OVERRIDE; |
| 167 |
| 168 private: |
| 169 scoped_ptr<WebFont> font_; |
| 170 |
| 171 DISALLOW_COPY_AND_ASSIGN(FontImpl); |
| 172 }; |
| 173 |
| 174 FontImpl::FontImpl(const PP_FontDescription_Dev& desc, |
| 175 const std::string& desc_face, |
| 176 const ::ppapi::Preferences& prefs) { |
| 177 WebFontDescription web_font_desc = PPFontDescToWebFontDesc(desc, desc_face, |
| 178 prefs); |
| 179 font_.reset(WebFont::create(web_font_desc)); |
| 180 } |
| 181 |
| 182 FontImpl::~FontImpl() { |
| 183 } |
| 184 |
| 185 void FontImpl::Describe(PP_FontDescription_Dev* description, |
| 186 std::string* face, |
| 187 PP_FontMetrics_Dev* metrics, |
| 188 PP_Bool* result) { |
| 189 TRACE_EVENT0("ppapi WebKit thread", "FontImpl::Describe"); |
| 190 if (description->face.type != PP_VARTYPE_UNDEFINED) { |
| 191 *result = PP_FALSE; |
| 192 } else { |
| 193 WebFontDescription web_desc = font_->fontDescription(); |
| 194 |
| 195 // While converting the other way in PPFontDescToWebFontDesc we validated |
| 196 // that the enums can be casted. |
| 197 description->face = PP_MakeUndefined(); |
| 198 description->family = |
| 199 static_cast<PP_FontFamily_Dev>(web_desc.genericFamily); |
| 200 description->size = static_cast<uint32_t>(web_desc.size); |
| 201 description->weight = static_cast<PP_FontWeight_Dev>(web_desc.weight); |
| 202 description->italic = web_desc.italic ? PP_TRUE : PP_FALSE; |
| 203 description->small_caps = web_desc.smallCaps ? PP_TRUE : PP_FALSE; |
| 204 description->letter_spacing = static_cast<int32_t>(web_desc.letterSpacing); |
| 205 description->word_spacing = static_cast<int32_t>(web_desc.wordSpacing); |
| 206 |
| 207 *face = UTF16ToUTF8(web_desc.family); |
| 208 |
| 209 metrics->height = font_->height(); |
| 210 metrics->ascent = font_->ascent(); |
| 211 metrics->descent = font_->descent(); |
| 212 metrics->line_spacing = font_->lineSpacing(); |
| 213 metrics->x_height = static_cast<int32_t>(font_->xHeight()); |
| 214 |
| 215 *result = PP_TRUE; |
| 216 } |
| 217 } |
| 218 |
| 219 void FontImpl::DrawTextAt(const DrawTextParams& params) { |
| 220 TRACE_EVENT0("ppapi WebKit thread", "FontImpl::DrawTextAt"); |
| 221 WebTextRun run = TextRunToWebTextRun(params.text); |
| 222 |
| 223 // Convert position and clip. |
| 224 WebFloatPoint web_position(static_cast<float>(params.position->x), |
| 225 static_cast<float>(params.position->y)); |
| 226 WebRect web_clip; |
| 227 if (!params.clip) { |
| 228 // Use entire canvas. SkCanvas doesn't have a size on it, so we just use |
| 229 // the current clip bounds. |
| 230 SkRect skclip; |
| 231 params.destination->getClipBounds(&skclip); |
| 232 web_clip = WebRect(skclip.fLeft, skclip.fTop, skclip.fRight - skclip.fLeft, |
| 233 skclip.fBottom - skclip.fTop); |
| 234 } else { |
| 235 web_clip = WebRect(params.clip->point.x, params.clip->point.y, |
| 236 params.clip->size.width, params.clip->size.height); |
| 237 } |
| 238 |
| 239 #if WEBKIT_USING_SKIA |
| 240 WebCanvas* canvas = params.destination; |
| 241 #elif WEBKIT_USING_CG |
| 242 WebCanvas* canvas = skia::GetBitmapContext(skia::GetTopDevice(*destination)); |
| 243 #else |
| 244 NOTIMPLEMENTED(); |
| 245 return; |
| 246 #endif |
| 247 font_->drawText(canvas, run, web_position, params.color, web_clip, |
| 248 params.image_data_is_opaque == PP_TRUE); |
| 249 } |
| 250 |
| 251 void FontImpl::MeasureText(const TextRun& text, int32_t* result) { |
| 252 TRACE_EVENT0("ppapi WebKit thread", "FontImpl::MeasureText"); |
| 253 *result = font_->calculateWidth(TextRunToWebTextRun(text)); |
| 254 } |
| 255 |
| 256 void FontImpl::CharacterOffsetForPixel(const TextRun& text, |
| 257 int32_t pixel_position, |
| 258 uint32_t* result) { |
| 259 TRACE_EVENT0("ppapi WebKit thread", "FontImpl::CharacterOffsetForPixel"); |
| 260 *result = static_cast<uint32_t>(font_->offsetForPosition( |
| 261 TextRunToWebTextRun(text), static_cast<float>(pixel_position))); |
| 262 } |
| 263 |
| 264 void FontImpl::PixelOffsetForCharacter(const TextRun& text, |
| 265 uint32_t char_offset, |
| 266 int32_t* result) { |
| 267 TRACE_EVENT0("ppapi WebKit thread", "FontImpl::PixelOffsetForCharacter"); |
| 268 WebTextRun run = TextRunToWebTextRun(text); |
| 269 if (char_offset >= run.text.length()) { |
| 270 *result = -1; |
| 271 } else { |
| 272 WebFloatRect rect = font_->selectionRectForText( |
| 273 run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset); |
| 274 *result = static_cast<int>(rect.width); |
| 275 } |
| 276 } |
| 277 |
| 278 } // namespace |
| 279 |
| 11 // static | 280 // static |
| 12 bool PPB_Font_Shared::IsPPFontDescriptionValid( | 281 bool PPB_Font_Shared::IsPPFontDescriptionValid( |
| 13 const PP_FontDescription_Dev& desc) { | 282 const PP_FontDescription_Dev& desc) { |
| 14 // Check validity of string. We can't check the actual text since we could | 283 // Check validity of string. We can't check the actual text since we could |
| 15 // be on the wrong thread and don't know if we're in the plugin or the host. | 284 // be on the wrong thread and don't know if we're in the plugin or the host. |
| 16 if (desc.face.type != PP_VARTYPE_STRING && | 285 if (desc.face.type != PP_VARTYPE_STRING && |
| 17 desc.face.type != PP_VARTYPE_UNDEFINED) | 286 desc.face.type != PP_VARTYPE_UNDEFINED) |
| 18 return false; | 287 return false; |
| 19 | 288 |
| 20 // Check enum ranges. | 289 // Check enum ranges. |
| 21 if (static_cast<int>(desc.family) < PP_FONTFAMILY_DEFAULT || | 290 if (static_cast<int>(desc.family) < PP_FONTFAMILY_DEFAULT || |
| 22 static_cast<int>(desc.family) > PP_FONTFAMILY_MONOSPACE) | 291 static_cast<int>(desc.family) > PP_FONTFAMILY_MONOSPACE) |
| 23 return false; | 292 return false; |
| 24 if (static_cast<int>(desc.weight) < PP_FONTWEIGHT_100 || | 293 if (static_cast<int>(desc.weight) < PP_FONTWEIGHT_100 || |
| 25 static_cast<int>(desc.weight) > PP_FONTWEIGHT_900) | 294 static_cast<int>(desc.weight) > PP_FONTWEIGHT_900) |
| 26 return false; | 295 return false; |
| 27 | 296 |
| 28 // Check for excessive sizes which may cause layout to get confused. | 297 // Check for excessive sizes which may cause layout to get confused. |
| 29 if (desc.size > 200) | 298 if (desc.size > 200) |
| 30 return false; | 299 return false; |
| 31 | 300 |
| 32 return true; | 301 return true; |
| 33 } | 302 } |
| 34 | 303 |
| 304 // static |
| 305 PP_Resource PPB_Font_Shared::CreateAsImpl( |
| 306 PP_Instance instance, |
| 307 const PP_FontDescription_Dev& description, |
| 308 const ::ppapi::Preferences& prefs) { |
| 309 if (!::ppapi::PPB_Font_Shared::IsPPFontDescriptionValid(description)) |
| 310 return 0; |
| 311 return (new PPB_Font_Shared(instance, description, prefs))->GetReference(); |
| 312 } |
| 313 |
| 314 // static |
| 315 PP_Resource PPB_Font_Shared::CreateAsProxy( |
| 316 PP_Instance instance, |
| 317 const PP_FontDescription_Dev& description, |
| 318 const ::ppapi::Preferences& prefs) { |
| 319 return CreateAsImpl(instance, description, prefs); |
| 320 } |
| 321 |
| 322 PPB_Font_Shared::PPB_Font_Shared(PP_Instance pp_instance, |
| 323 const PP_FontDescription_Dev& desc, |
| 324 const ::ppapi::Preferences& prefs) |
| 325 : Resource(pp_instance) { |
| 326 StringVar* face_name = StringVar::FromPPVar(desc.face); |
| 327 |
| 328 font_impl_.reset(new FontImpl( |
| 329 desc, face_name ? face_name->value() : std::string(), prefs)); |
| 330 } |
| 331 |
| 332 PPB_Font_Shared::~PPB_Font_Shared() { |
| 333 } |
| 334 |
| 335 ::ppapi::thunk::PPB_Font_API* PPB_Font_Shared::AsPPB_Font_API() { |
| 336 return this; |
| 337 } |
| 338 |
| 339 PP_Bool PPB_Font_Shared::Describe(PP_FontDescription_Dev* description, |
| 340 PP_FontMetrics_Dev* metrics) { |
| 341 std::string face; |
| 342 PP_Bool result = PP_FALSE; |
| 343 font_impl_->Describe(description, &face, metrics, &result); |
| 344 if (!result) |
| 345 return PP_FALSE; |
| 346 |
| 347 // Convert the string. |
| 348 description->face = StringVar::StringToPPVar(face); |
| 349 return PP_TRUE; |
| 350 } |
| 351 |
| 352 PP_Bool PPB_Font_Shared::DrawTextAt(PP_Resource image_data, |
| 353 const PP_TextRun_Dev* text, |
| 354 const PP_Point* position, |
| 355 uint32_t color, |
| 356 const PP_Rect* clip, |
| 357 PP_Bool image_data_is_opaque) { |
| 358 PP_Bool result = PP_FALSE; |
| 359 // Get and map the image data we're painting to. |
| 360 EnterResource<PPB_ImageData_API> enter(image_data, true); |
| 361 if (enter.failed()) |
| 362 return result; |
| 363 |
| 364 // TODO(ananta) |
| 365 // We need to remove dependency on skia from this layer. |
| 366 PPB_ImageData_API* image = static_cast<PPB_ImageData_API*>( |
| 367 enter.object()); |
| 368 skia::PlatformCanvas* canvas = image->GetPlatformCanvas(); |
| 369 bool needs_unmapping = false; |
| 370 if (!canvas) { |
| 371 needs_unmapping = true; |
| 372 image->Map(); |
| 373 canvas = image->GetPlatformCanvas(); |
| 374 if (!canvas) |
| 375 return result; // Failure mapping. |
| 376 } |
| 377 |
| 378 WebKitForwarding::Font::TextRun run; |
| 379 if (PPTextRunToTextRun(text, &run)) { |
| 380 font_impl_->DrawTextAt(WebKitForwarding::Font::DrawTextParams( |
| 381 canvas, run, position, color, clip, image_data_is_opaque)); |
| 382 result = PP_TRUE; |
| 383 } |
| 384 |
| 385 if (needs_unmapping) |
| 386 image->Unmap(); |
| 387 return result; |
| 388 } |
| 389 |
| 390 int32_t PPB_Font_Shared::MeasureText(const PP_TextRun_Dev* text) { |
| 391 int32_t result = -1; |
| 392 WebKitForwarding::Font::TextRun run; |
| 393 if (PPTextRunToTextRun(text, &run)) |
| 394 font_impl_->MeasureText(run, &result); |
| 395 return result; |
| 396 } |
| 397 |
| 398 uint32_t PPB_Font_Shared::CharacterOffsetForPixel(const PP_TextRun_Dev* text, |
| 399 int32_t pixel_position) { |
| 400 uint32_t result = -1; |
| 401 WebKitForwarding::Font::TextRun run; |
| 402 if (PPTextRunToTextRun(text, &run)) { |
| 403 font_impl_->CharacterOffsetForPixel(run, pixel_position, &result); |
| 404 } |
| 405 return result; |
| 406 } |
| 407 |
| 408 int32_t PPB_Font_Shared::PixelOffsetForCharacter(const PP_TextRun_Dev* text, |
| 409 uint32_t char_offset) { |
| 410 int32_t result = -1; |
| 411 WebKitForwarding::Font::TextRun run; |
| 412 if (PPTextRunToTextRun(text, &run)) { |
| 413 font_impl_->PixelOffsetForCharacter(run, char_offset, &result); |
| 414 } |
| 415 return result; |
| 416 } |
| 417 |
| 35 } // namespace ppapi | 418 } // namespace ppapi |
| 419 |
| OLD | NEW |