// 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 #include #include "base/containers/mru_cache.h" #include "base/debug/crash_logging.h" #include "base/lazy_instance.h" #include "base/time/time.h" #include "build/build_config.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 { public: LocalTimeZoneOffsetCache() : base::MRUCache(kCacheSize) {} private: static const size_t kCacheSize = 100; }; base::LazyInstance::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(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_t 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( 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(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 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(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 enter(request_info, true); if (enter.failed()) return PP_ERROR_BADRESOURCE; return SyncCall(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(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