blob: a1b810eacf74942ea8b72436623a40b0808b57e5 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "webkit/plugins/ppapi/webkit_forwarding_impl.h"
#include <string>
#include "base/debug/trace_event.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/utf_string_conversions.h"
#include "ppapi/c/dev/ppb_font_dev.h"
#include "ppapi/c/pp_point.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/shared_impl/ppapi_preferences.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCanvas.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFont.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFontDescription.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFloatPoint.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFloatRect.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebTextRun.h"
#include "webkit/glue/webkit_glue.h"
using ::ppapi::WebKitForwarding;
using WebKit::WebCanvas;
using WebKit::WebFloatPoint;
using WebKit::WebFloatRect;
using WebKit::WebFont;
using WebKit::WebFontDescription;
using WebKit::WebRect;
using WebKit::WebTextRun;
namespace webkit {
namespace ppapi {
namespace {
// The PP_* version lacks "None", so is just one value shifted from the
// WebFontDescription version. These values are checked in
// PPFontDescToWebFontDesc to make sure the conversion is correct. This is a
// macro so it can also be used in the COMPILE_ASSERTS.
#define PP_FONTFAMILY_TO_WEB_FONTFAMILY(f) \
static_cast<WebFontDescription::GenericFamily>(f + 1)
// Assumes the given PP_FontDescription has been validated.
WebFontDescription PPFontDescToWebFontDesc(const PP_FontDescription_Dev& font,
const std::string& face,
const ::ppapi::Preferences& prefs) {
// Verify that the enums match so we can just static cast.
COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight100) ==
static_cast<int>(PP_FONTWEIGHT_100),
FontWeight100);
COMPILE_ASSERT(static_cast<int>(WebFontDescription::Weight900) ==
static_cast<int>(PP_FONTWEIGHT_900),
FontWeight900);
COMPILE_ASSERT(WebFontDescription::GenericFamilyStandard ==
PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_DEFAULT),
StandardFamily);
COMPILE_ASSERT(WebFontDescription::GenericFamilySerif ==
PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SERIF),
SerifFamily);
COMPILE_ASSERT(WebFontDescription::GenericFamilySansSerif ==
PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_SANSSERIF),
SansSerifFamily);
COMPILE_ASSERT(WebFontDescription::GenericFamilyMonospace ==
PP_FONTFAMILY_TO_WEB_FONTFAMILY(PP_FONTFAMILY_MONOSPACE),
MonospaceFamily);
WebFontDescription result;
string16 resolved_family;
if (face.empty()) {
// Resolve the generic family.
switch (font.family) {
case PP_FONTFAMILY_SERIF:
resolved_family = prefs.serif_font_family;
break;
case PP_FONTFAMILY_SANSSERIF:
resolved_family = prefs.sans_serif_font_family;
break;
case PP_FONTFAMILY_MONOSPACE:
resolved_family = prefs.fixed_font_family;
break;
case PP_FONTFAMILY_DEFAULT:
default:
resolved_family = prefs.standard_font_family;
break;
}
} else {
// Use the exact font.
resolved_family = UTF8ToUTF16(face);
}
result.family = resolved_family;
result.genericFamily = PP_FONTFAMILY_TO_WEB_FONTFAMILY(font.family);
if (font.size == 0) {
// Resolve the default font size, using the resolved family to see if
// we should use the fixed or regular font size. It's difficult at this
// level to detect if the requested font is fixed width, so we only apply
// the alternate font size to the default fixed font family.
if (StringToLowerASCII(resolved_family) ==
StringToLowerASCII(prefs.fixed_font_family))
result.size = static_cast<float>(prefs.default_fixed_font_size);
else
result.size = static_cast<float>(prefs.default_font_size);
} else {
// Use the exact size.
result.size = static_cast<float>(font.size);
}
result.italic = font.italic != PP_FALSE;
result.smallCaps = font.small_caps != PP_FALSE;
result.weight = static_cast<WebFontDescription::Weight>(font.weight);
result.letterSpacing = static_cast<short>(font.letter_spacing);
result.wordSpacing = static_cast<short>(font.word_spacing);
return result;
}
WebTextRun TextRunToWebTextRun(const WebKitForwarding::Font::TextRun& run) {
return WebTextRun(UTF8ToUTF16(run.text),
run.rtl != PP_FALSE,
run.override_direction != PP_FALSE);
}
// FontImpl --------------------------------------------------------------------
class FontImpl : public WebKitForwarding::Font {
public:
FontImpl(const PP_FontDescription_Dev& desc,
const std::string& desc_face,
const ::ppapi::Preferences& prefs);
virtual ~FontImpl();
virtual void Describe(base::WaitableEvent* event,
PP_FontDescription_Dev* description,
std::string* face,
PP_FontMetrics_Dev* metrics,
PP_Bool* result) OVERRIDE;
virtual void DrawTextAt(base::WaitableEvent* event,
const DrawTextParams& params) OVERRIDE;
virtual void MeasureText(base::WaitableEvent* event,
const TextRun& text,
int32_t* result) OVERRIDE;
virtual void CharacterOffsetForPixel(base::WaitableEvent* event,
const TextRun& text,
int32_t pixel_position,
uint32_t* result) OVERRIDE;
virtual void PixelOffsetForCharacter(base::WaitableEvent* event,
const TextRun& text,
uint32_t char_offset,
int32_t* result) OVERRIDE;
private:
scoped_ptr<WebFont> font_;
DISALLOW_COPY_AND_ASSIGN(FontImpl);
};
FontImpl::FontImpl(const PP_FontDescription_Dev& desc,
const std::string& desc_face,
const ::ppapi::Preferences& prefs) {
WebFontDescription web_font_desc = PPFontDescToWebFontDesc(desc, desc_face,
prefs);
font_.reset(WebFont::create(web_font_desc));
}
FontImpl::~FontImpl() {
}
void FontImpl::Describe(base::WaitableEvent* event,
PP_FontDescription_Dev* description,
std::string* face,
PP_FontMetrics_Dev* metrics,
PP_Bool* result) {
TRACE_EVENT0("ppapi WebKit thread", "FontImpl::Describe");
if (description->face.type != PP_VARTYPE_UNDEFINED) {
*result = PP_FALSE;
} else {
WebFontDescription web_desc = font_->fontDescription();
// While converting the other way in PPFontDescToWebFontDesc we validated
// that the enums can be casted.
description->face = PP_MakeUndefined();
description->family =
static_cast<PP_FontFamily_Dev>(web_desc.genericFamily);
description->size = static_cast<uint32_t>(web_desc.size);
description->weight = static_cast<PP_FontWeight_Dev>(web_desc.weight);
description->italic = web_desc.italic ? PP_TRUE : PP_FALSE;
description->small_caps = web_desc.smallCaps ? PP_TRUE : PP_FALSE;
*face = UTF16ToUTF8(web_desc.family);
metrics->height = font_->height();
metrics->ascent = font_->ascent();
metrics->descent = font_->descent();
metrics->line_spacing = font_->lineSpacing();
metrics->x_height = static_cast<int32_t>(font_->xHeight());
*result = PP_TRUE;
}
if (event)
event->Signal();
}
void FontImpl::DrawTextAt(base::WaitableEvent* event,
const DrawTextParams& params) {
TRACE_EVENT0("ppapi WebKit thread", "FontImpl::DrawTextAt");
WebTextRun run = TextRunToWebTextRun(params.text);
// Convert position and clip.
WebFloatPoint web_position(static_cast<float>(params.position->x),
static_cast<float>(params.position->y));
WebRect web_clip;
if (!params.clip) {
// Use entire canvas. SkCanvas doesn't have a size on it, so we just use
// the current clip bounds.
SkRect skclip;
params.destination->getClipBounds(&skclip);
web_clip = WebRect(skclip.fLeft, skclip.fTop, skclip.fRight - skclip.fLeft,
skclip.fBottom - skclip.fTop);
} else {
web_clip = WebRect(params.clip->point.x, params.clip->point.y,
params.clip->size.width, params.clip->size.height);
}
font_->drawText(webkit_glue::ToWebCanvas(params.destination), run,
web_position, params.color, web_clip,
params.image_data_is_opaque == PP_TRUE);
if (event)
event->Signal();
}
void FontImpl::MeasureText(base::WaitableEvent* event,
const TextRun& text, int32_t* result) {
TRACE_EVENT0("ppapi WebKit thread", "FontImpl::MeasureText");
*result = font_->calculateWidth(TextRunToWebTextRun(text));
if (event)
event->Signal();
}
void FontImpl::CharacterOffsetForPixel(base::WaitableEvent* event,
const TextRun& text,
int32_t pixel_position,
uint32_t* result) {
TRACE_EVENT0("ppapi WebKit thread", "FontImpl::CharacterOffsetForPixel");
*result = static_cast<uint32_t>(font_->offsetForPosition(
TextRunToWebTextRun(text), static_cast<float>(pixel_position)));
if (event)
event->Signal();
}
void FontImpl::PixelOffsetForCharacter(base::WaitableEvent* event,
const TextRun& text,
uint32_t char_offset,
int32_t* result) {
TRACE_EVENT0("ppapi WebKit thread", "FontImpl::PixelOffsetForCharacter");
WebTextRun run = TextRunToWebTextRun(text);
if (char_offset >= run.text.length()) {
*result = -1;
} else {
WebFloatRect rect = font_->selectionRectForText(
run, WebFloatPoint(0.0f, 0.0f), font_->height(), 0, char_offset);
*result = static_cast<int>(rect.width);
}
if (event)
event->Signal();
}
} // namespace
// WebKitForwardingImpl --------------------------------------------------------
WebKitForwardingImpl::WebKitForwardingImpl() {
}
WebKitForwardingImpl::~WebKitForwardingImpl() {
}
void WebKitForwardingImpl::CreateFontForwarding(
base::WaitableEvent* event,
const PP_FontDescription_Dev& desc,
const std::string& desc_face,
const ::ppapi::Preferences& prefs,
Font** result) {
TRACE_EVENT0("ppapi WebKit thread",
"WebKitForwardingImpl::CreateFontForwarding");
*result = new FontImpl(desc, desc_face, prefs);
if (event)
event->Signal();
}
} // namespace ppapi
} // namespace webkit