1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ppapi/proxy/flash_resource.h" 6 7 #include <cmath> 8 9 #include "base/containers/mru_cache.h" 10 #include "base/debug/crash_logging.h" 11 #include "base/lazy_instance.h" 12 #include "base/time/time.h" 13 #include "ppapi/c/pp_errors.h" 14 #include "ppapi/c/private/ppb_flash.h" 15 #include "ppapi/c/trusted/ppb_browser_font_trusted.h" 16 #include "ppapi/proxy/plugin_dispatcher.h" 17 #include "ppapi/proxy/plugin_globals.h" 18 #include "ppapi/proxy/ppapi_messages.h" 19 #include "ppapi/proxy/serialized_structs.h" 20 #include "ppapi/shared_impl/ppapi_preferences.h" 21 #include "ppapi/shared_impl/scoped_pp_var.h" 22 #include "ppapi/shared_impl/time_conversion.h" 23 #include "ppapi/shared_impl/var.h" 24 #include "ppapi/thunk/enter.h" 25 #include "ppapi/thunk/ppb_url_request_info_api.h" 26 27 using ppapi::thunk::EnterResourceNoLock; 28 29 namespace ppapi { 30 namespace proxy { 31 32 namespace { 33 34 struct LocalTimeZoneOffsetEntry { 35 base::TimeTicks expiration; 36 double offset; 37 }; 38 39 class LocalTimeZoneOffsetCache 40 : public base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry> { 41 public: 42 LocalTimeZoneOffsetCache() 43 : base::MRUCache<PP_Time, LocalTimeZoneOffsetEntry>(kCacheSize) {} 44 private: 45 static const size_t kCacheSize = 100; 46 }; 47 48 base::LazyInstance<LocalTimeZoneOffsetCache>::Leaky 49 g_local_time_zone_offset_cache = LAZY_INSTANCE_INITIALIZER; 50 51 } // namespace 52 53 FlashResource::FlashResource(Connection connection, 54 PP_Instance instance, 55 PluginDispatcher* plugin_dispatcher) 56 : PluginResource(connection, instance), 57 plugin_dispatcher_(plugin_dispatcher) { 58 SendCreate(RENDERER, PpapiHostMsg_Flash_Create()); 59 SendCreate(BROWSER, PpapiHostMsg_Flash_Create()); 60 } 61 62 FlashResource::~FlashResource() { 63 } 64 65 thunk::PPB_Flash_Functions_API* FlashResource::AsPPB_Flash_Functions_API() { 66 return this; 67 } 68 69 PP_Var FlashResource::GetProxyForURL(PP_Instance instance, 70 const std::string& url) { 71 std::string proxy; 72 int32_t result = SyncCall<PpapiPluginMsg_Flash_GetProxyForURLReply>(RENDERER, 73 PpapiHostMsg_Flash_GetProxyForURL(url), &proxy); 74 75 if (result == PP_OK) 76 return StringVar::StringToPPVar(proxy); 77 return PP_MakeUndefined(); 78 } 79 80 void FlashResource::UpdateActivity(PP_Instance instance) { 81 Post(BROWSER, PpapiHostMsg_Flash_UpdateActivity()); 82 } 83 84 PP_Bool FlashResource::SetCrashData(PP_Instance instance, 85 PP_FlashCrashKey key, 86 PP_Var value) { 87 StringVar* url_string_var(StringVar::FromPPVar(value)); 88 if (!url_string_var) 89 return PP_FALSE; 90 switch (key) { 91 case PP_FLASHCRASHKEY_URL: { 92 PluginGlobals::Get()->SetActiveURL(url_string_var->value()); 93 return PP_TRUE; 94 } 95 case PP_FLASHCRASHKEY_RESOURCE_URL: { 96 base::debug::SetCrashKeyValue("subresource_url", url_string_var->value()); 97 return PP_TRUE; 98 } 99 } 100 return PP_FALSE; 101 } 102 103 double FlashResource::GetLocalTimeZoneOffset(PP_Instance instance, 104 PP_Time t) { 105 LocalTimeZoneOffsetCache& cache = g_local_time_zone_offset_cache.Get(); 106 107 // Get the minimum PP_Time value that shares the same minute as |t|. 108 // Use cached offset if cache hasn't expired and |t| is in the same minute as 109 // the time for the cached offset (assume offsets change on minute 110 // boundaries). 111 PP_Time t_minute_base = floor(t / 60.0) * 60.0; 112 LocalTimeZoneOffsetCache::iterator iter = cache.Get(t_minute_base); 113 base::TimeTicks now = base::TimeTicks::Now(); 114 if (iter != cache.end() && now < iter->second.expiration) 115 return iter->second.offset; 116 117 // Cache the local offset for ten seconds, since it's slow on XP and Linux. 118 // Note that TimeTicks does not continue counting across sleep/resume on all 119 // platforms. This may be acceptable for 10 seconds, but if in the future this 120 // is changed to one minute or more, then we should consider using base::Time. 121 const int64 kMaxCachedLocalOffsetAgeInSeconds = 10; 122 base::TimeDelta expiration_delta = 123 base::TimeDelta::FromSeconds(kMaxCachedLocalOffsetAgeInSeconds); 124 125 LocalTimeZoneOffsetEntry cache_entry; 126 cache_entry.expiration = now + expiration_delta; 127 cache_entry.offset = 0.0; 128 129 // We can't do the conversion here on Linux because the localtime calls 130 // require filesystem access prohibited by the sandbox. 131 // TODO(shess): Figure out why OSX needs the access, the sandbox warmup should 132 // handle it. http://crbug.com/149006 133 #if defined(OS_LINUX) || defined(OS_MACOSX) 134 int32_t result = SyncCall<PpapiPluginMsg_Flash_GetLocalTimeZoneOffsetReply>( 135 BROWSER, 136 PpapiHostMsg_Flash_GetLocalTimeZoneOffset(PPTimeToTime(t)), 137 &cache_entry.offset); 138 if (result != PP_OK) 139 cache_entry.offset = 0.0; 140 #else 141 cache_entry.offset = PPGetLocalTimeZoneOffset(PPTimeToTime(t)); 142 #endif 143 144 cache.Put(t_minute_base, cache_entry); 145 return cache_entry.offset; 146 } 147 148 PP_Var FlashResource::GetSetting(PP_Instance instance, 149 PP_FlashSetting setting) { 150 switch (setting) { 151 case PP_FLASHSETTING_3DENABLED: 152 return PP_MakeBool(PP_FromBool( 153 plugin_dispatcher_->preferences().is_3d_supported)); 154 case PP_FLASHSETTING_INCOGNITO: 155 return PP_MakeBool(PP_FromBool(plugin_dispatcher_->incognito())); 156 case PP_FLASHSETTING_STAGE3DENABLED: 157 return PP_MakeBool(PP_FromBool( 158 plugin_dispatcher_->preferences().is_stage3d_supported)); 159 case PP_FLASHSETTING_STAGE3DBASELINEENABLED: 160 return PP_MakeBool(PP_FromBool( 161 plugin_dispatcher_->preferences().is_stage3d_baseline_supported)); 162 case PP_FLASHSETTING_LANGUAGE: 163 return StringVar::StringToPPVar( 164 PluginGlobals::Get()->GetUILanguage()); 165 case PP_FLASHSETTING_NUMCORES: 166 return PP_MakeInt32( 167 plugin_dispatcher_->preferences().number_of_cpu_cores); 168 case PP_FLASHSETTING_LSORESTRICTIONS: { 169 int32_t restrictions; 170 int32_t result = 171 SyncCall<PpapiPluginMsg_Flash_GetLocalDataRestrictionsReply>(BROWSER, 172 PpapiHostMsg_Flash_GetLocalDataRestrictions(), &restrictions); 173 if (result != PP_OK) 174 return PP_MakeInt32(PP_FLASHLSORESTRICTIONS_NONE); 175 return PP_MakeInt32(restrictions); 176 } 177 } 178 return PP_MakeUndefined(); 179 } 180 181 void FlashResource::SetInstanceAlwaysOnTop(PP_Instance instance, 182 PP_Bool on_top) { 183 Post(RENDERER, PpapiHostMsg_Flash_SetInstanceAlwaysOnTop(PP_ToBool(on_top))); 184 } 185 186 PP_Bool FlashResource::DrawGlyphs( 187 PP_Instance instance, 188 PP_Resource pp_image_data, 189 const PP_BrowserFont_Trusted_Description* font_desc, 190 uint32_t color, 191 const PP_Point* position, 192 const PP_Rect* clip, 193 const float transformation[3][3], 194 PP_Bool allow_subpixel_aa, 195 uint32_t glyph_count, 196 const uint16_t glyph_indices[], 197 const PP_Point glyph_advances[]) { 198 EnterResourceNoLock<thunk::PPB_ImageData_API> enter(pp_image_data, true); 199 if (enter.failed()) 200 return PP_FALSE; 201 // The instance parameter isn't strictly necessary but we check that it 202 // matches anyway. 203 if (enter.resource()->pp_instance() != instance) 204 return PP_FALSE; 205 206 PPBFlash_DrawGlyphs_Params params; 207 params.image_data = enter.resource()->host_resource(); 208 params.font_desc.SetFromPPBrowserFontDescription(*font_desc); 209 params.color = color; 210 params.position = *position; 211 params.clip = *clip; 212 for (int i = 0; i < 3; i++) { 213 for (int j = 0; j < 3; j++) 214 params.transformation[i][j] = transformation[i][j]; 215 } 216 params.allow_subpixel_aa = allow_subpixel_aa; 217 218 params.glyph_indices.insert(params.glyph_indices.begin(), 219 &glyph_indices[0], 220 &glyph_indices[glyph_count]); 221 params.glyph_advances.insert(params.glyph_advances.begin(), 222 &glyph_advances[0], 223 &glyph_advances[glyph_count]); 224 225 // This has to be synchronous because the caller may want to composite on 226 // top of the resulting text after the call is complete. 227 int32_t result = SyncCall<IPC::Message>(RENDERER, 228 PpapiHostMsg_Flash_DrawGlyphs(params)); 229 return PP_FromBool(result == PP_OK); 230 } 231 232 int32_t FlashResource::Navigate(PP_Instance instance, 233 PP_Resource request_info, 234 const char* target, 235 PP_Bool from_user_action) { 236 EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_info, 237 true); 238 if (enter.failed()) 239 return PP_ERROR_BADRESOURCE; 240 return SyncCall<IPC::Message>(RENDERER, PpapiHostMsg_Flash_Navigate( 241 enter.object()->GetData(), target, PP_ToBool(from_user_action))); 242 } 243 244 PP_Bool FlashResource::IsRectTopmost(PP_Instance instance, 245 const PP_Rect* rect) { 246 int32_t result = SyncCall<IPC::Message>(RENDERER, 247 PpapiHostMsg_Flash_IsRectTopmost(*rect)); 248 return PP_FromBool(result == PP_OK); 249 } 250 251 void FlashResource::InvokePrinting(PP_Instance instance) { 252 Post(RENDERER, PpapiHostMsg_Flash_InvokePrinting()); 253 } 254 255 } // namespace proxy 256 } // namespace ppapi 257