blob: 26a80ae8222889dc0c873fb53198c333472170c0 [file] [log] [blame]
// Copyright (c) 2012 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 "ppapi/proxy/flash_resource.h"
#include <cmath>
#include "base/containers/mru_cache.h"
#include "base/debug/crash_logging.h"
#include "base/lazy_instance.h"
#include "base/time/time.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_flash.h"
#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/serialized_structs.h"
#include "ppapi/shared_impl/ppapi_preferences.h"
#include "ppapi/shared_impl/scoped_pp_var.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/shared_impl/var.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_url_request_info_api.h"
using ppapi::thunk::EnterResourceNoLock;
namespace ppapi {
namespace proxy {
namespace {
struct LocalTimeZoneOffsetEntry {
base::TimeTicks expiration;
double offset;
};
class LocalTimeZoneOffsetCache
: public base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry> {
public:
LocalTimeZoneOffsetCache()
: base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry>(kCacheSize) {}
private:
static const size_t kCacheSize = 100;
};
base::LazyInstance<LocalTimeZoneOffsetCache>::Leaky
g_local_time_zone_offset_cache = LAZY_INSTANCE_INITIALIZER;
} // namespace
FlashResource::FlashResource(Connection connection,
PP_Instance instance,
PluginDispatcher* plugin_dispatcher)
: PluginResource(connection, instance),
plugin_dispatcher_(plugin_dispatcher) {
SendCreate(RENDERER, PpapiHostMsg_Flash_Create());
SendCreate(BROWSER, PpapiHostMsg_Flash_Create());
}
FlashResource::~FlashResource() {
}
thunk::PPB_Flash_Functions_API* FlashResource::AsPPB_Flash_Functions_API() {
return this;
}
PP_Var FlashResource::GetProxyForURL(PP_Instance instance,
const std::string& url) {
std::string proxy;
int32_t result = SyncCall<PpapiPluginMsg_Flash_GetProxyForURLReply>(RENDERER,
PpapiHostMsg_Flash_GetProxyForURL(url), &proxy);
if (result == PP_OK)
return StringVar::StringToPPVar(proxy);
return PP_MakeUndefined();
}
void FlashResource::UpdateActivity(PP_Instance instance) {
Post(BROWSER, PpapiHostMsg_Flash_UpdateActivity());
}
PP_Bool FlashResource::SetCrashData(PP_Instance instance,
PP_FlashCrashKey key,
PP_Var value) {
StringVar* url_string_var(StringVar::FromPPVar(value));
if (!url_string_var)
return PP_FALSE;
switch (key) {
case PP_FLASHCRASHKEY_URL: {
PluginGlobals::Get()->SetActiveURL(url_string_var->value());
return PP_TRUE;
}
case PP_FLASHCRASHKEY_RESOURCE_URL: {
base::debug::SetCrashKeyValue("subresource_url", url_string_var->value());
return PP_TRUE;
}
}
return PP_FALSE;
}
double FlashResource::GetLocalTimeZoneOffset(PP_Instance instance,
PP_Time t) {
LocalTimeZoneOffsetCache& cache = g_local_time_zone_offset_cache.Get();
// Get the minimum PP_Time value that shares the same minute as |t|.
// Use cached offset if cache hasn't expired and |t| is in the same minute as
// the time for the cached offset (assume offsets change on minute
// boundaries).
PP_Time t_minute_base = floor(t / 60.0) * 60.0;
LocalTimeZoneOffsetCache::iterator iter = cache.Get(t_minute_base);
base::TimeTicks now = base::TimeTicks::Now();
if (iter != cache.end() && now < iter->second.expiration)
return iter->second.offset;
// Cache the local offset for ten seconds, since it's slow on XP and Linux.
// Note that TimeTicks does not continue counting across sleep/resume on all
// platforms. This may be acceptable for 10 seconds, but if in the future this
// is changed to one minute or more, then we should consider using base::Time.
const int64 kMaxCachedLocalOffsetAgeInSeconds = 10;
base::TimeDelta expiration_delta =
base::TimeDelta::FromSeconds(kMaxCachedLocalOffsetAgeInSeconds);
LocalTimeZoneOffsetEntry cache_entry;
cache_entry.expiration = now + expiration_delta;
cache_entry.offset = 0.0;
// We can't do the conversion here on Linux because the localtime calls
// require filesystem access prohibited by the sandbox.
// TODO(shess): Figure out why OSX needs the access, the sandbox warmup should
// handle it. http://crbug.com/149006
#if defined(OS_LINUX) || defined(OS_MACOSX)
int32_t result = SyncCall<PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply>(
BROWSER,
PpapiHostMsg_Flash_GetLocalTimeZoneOffset(PPTimeToTime(t)),
&cache_entry.offset);
if (result != PP_OK)
cache_entry.offset = 0.0;
#else
cache_entry.offset = PPGetLocalTimeZoneOffset(PPTimeToTime(t));
#endif
cache.Put(t_minute_base, cache_entry);
return cache_entry.offset;
}
PP_Var FlashResource::GetSetting(PP_Instance instance,
PP_FlashSetting setting) {
switch (setting) {
case PP_FLASHSETTING_3DENABLED:
return PP_MakeBool(PP_FromBool(
plugin_dispatcher_->preferences().is_3d_supported));
case PP_FLASHSETTING_INCOGNITO:
return PP_MakeBool(PP_FromBool(plugin_dispatcher_->incognito()));
case PP_FLASHSETTING_STAGE3DENABLED:
return PP_MakeBool(PP_FromBool(
plugin_dispatcher_->preferences().is_stage3d_supported));
case PP_FLASHSETTING_STAGE3DBASELINEENABLED:
return PP_MakeBool(PP_FromBool(
plugin_dispatcher_->preferences().is_stage3d_baseline_supported));
case PP_FLASHSETTING_LANGUAGE:
return StringVar::StringToPPVar(
PluginGlobals::Get()->GetUILanguage());
case PP_FLASHSETTING_NUMCORES:
return PP_MakeInt32(
plugin_dispatcher_->preferences().number_of_cpu_cores);
case PP_FLASHSETTING_LSORESTRICTIONS: {
int32_t restrictions;
int32_t result =
SyncCall<PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply>(BROWSER,
PpapiHostMsg_Flash_GetLocalDataRestrictions(), &restrictions);
if (result != PP_OK)
return PP_MakeInt32(PP_FLASHLSORESTRICTIONS_NONE);
return PP_MakeInt32(restrictions);
}
}
return PP_MakeUndefined();
}
void FlashResource::SetInstanceAlwaysOnTop(PP_Instance instance,
PP_Bool on_top) {
Post(RENDERER, PpapiHostMsg_Flash_SetInstanceAlwaysOnTop(PP_ToBool(on_top)));
}
PP_Bool FlashResource::DrawGlyphs(
PP_Instance instance,
PP_Resource pp_image_data,
const PP_BrowserFont_Trusted_Description* font_desc,
uint32_t color,
const PP_Point* position,
const PP_Rect* clip,
const float transformation[3][3],
PP_Bool allow_subpixel_aa,
uint32_t glyph_count,
const uint16_t glyph_indices[],
const PP_Point glyph_advances[]) {
EnterResourceNoLock<thunk::PPB_ImageData_API> enter(pp_image_data, true);
if (enter.failed())
return PP_FALSE;
// The instance parameter isn't strictly necessary but we check that it
// matches anyway.
if (enter.resource()->pp_instance() != instance)
return PP_FALSE;
PPBFlash_DrawGlyphs_Params params;
params.image_data = enter.resource()->host_resource();
params.font_desc.SetFromPPBrowserFontDescription(*font_desc);
params.color = color;
params.position = *position;
params.clip = *clip;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
params.transformation[i][j] = transformation[i][j];
}
params.allow_subpixel_aa = allow_subpixel_aa;
params.glyph_indices.insert(params.glyph_indices.begin(),
&glyph_indices[0],
&glyph_indices[glyph_count]);
params.glyph_advances.insert(params.glyph_advances.begin(),
&glyph_advances[0],
&glyph_advances[glyph_count]);
// This has to be synchronous because the caller may want to composite on
// top of the resulting text after the call is complete.
int32_t result = SyncCall<IPC::Message>(RENDERER,
PpapiHostMsg_Flash_DrawGlyphs(params));
return PP_FromBool(result == PP_OK);
}
int32_t FlashResource::Navigate(PP_Instance instance,
PP_Resource request_info,
const char* target,
PP_Bool from_user_action) {
EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_info,
true);
if (enter.failed())
return PP_ERROR_BADRESOURCE;
return SyncCall<IPC::Message>(RENDERER, PpapiHostMsg_Flash_Navigate(
enter.object()->GetData(), target, PP_ToBool(from_user_action)));
}
PP_Bool FlashResource::IsRectTopmost(PP_Instance instance,
const PP_Rect* rect) {
int32_t result = SyncCall<IPC::Message>(RENDERER,
PpapiHostMsg_Flash_IsRectTopmost(*rect));
return PP_FromBool(result == PP_OK);
}
void FlashResource::InvokePrinting(PP_Instance instance) {
Post(RENDERER, PpapiHostMsg_Flash_InvokePrinting());
}
} // namespace proxy
} // namespace ppapi