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