|  | // 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 <stddef.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 "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<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_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<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 |