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.
5 #include "chrome/renderer/pepper/pepper_flash_renderer_host.h"
9 #include "chrome/renderer/pepper/ppb_pdf_impl.h"
10 #include "content/public/renderer/pepper_plugin_instance.h"
11 #include "content/public/renderer/render_thread.h"
12 #include "content/public/renderer/renderer_ppapi_host.h"
13 #include "ipc/ipc_message_macros.h"
14 #include "ppapi/c/pp_errors.h"
15 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
16 #include "ppapi/host/dispatch_host_message.h"
17 #include "ppapi/proxy/host_dispatcher.h"
18 #include "ppapi/proxy/ppapi_messages.h"
19 #include "ppapi/proxy/resource_message_params.h"
20 #include "ppapi/proxy/serialized_structs.h"
21 #include "ppapi/thunk/enter.h"
22 #include "ppapi/thunk/ppb_image_data_api.h"
23 #include "skia/ext/platform_canvas.h"
24 #include "third_party/skia/include/core/SkCanvas.h"
25 #include "third_party/skia/include/core/SkMatrix.h"
26 #include "third_party/skia/include/core/SkPaint.h"
27 #include "third_party/skia/include/core/SkPoint.h"
28 #include "third_party/skia/include/core/SkTemplates.h"
29 #include "third_party/skia/include/core/SkTypeface.h"
30 #include "ui/gfx/rect.h"
33 using ppapi::thunk::EnterResourceNoLock
;
34 using ppapi::thunk::PPB_ImageData_API
;
36 PepperFlashRendererHost::PepperFlashRendererHost(
37 content::RendererPpapiHost
* host
,
40 : ResourceHost(host
->GetPpapiHost(), instance
, resource
),
45 PepperFlashRendererHost::~PepperFlashRendererHost() {
46 // This object may be destroyed in the middle of a sync message. If that is
47 // the case, make sure we respond to all the pending navigate calls.
48 std::vector
<ppapi::host::ReplyMessageContext
>::reverse_iterator it
;
49 for (it
= navigate_replies_
.rbegin(); it
!= navigate_replies_
.rend(); ++it
)
50 SendReply(*it
, IPC::Message());
53 int32_t PepperFlashRendererHost::OnResourceMessageReceived(
54 const IPC::Message
& msg
,
55 ppapi::host::HostMessageContext
* context
) {
56 IPC_BEGIN_MESSAGE_MAP(PepperFlashRendererHost
, msg
)
57 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetProxyForURL
,
59 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop
,
60 OnSetInstanceAlwaysOnTop
);
61 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_DrawGlyphs
,
63 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_Navigate
,
65 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_IsRectTopmost
,
67 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_InvokePrinting
,
70 return PP_ERROR_FAILED
;
73 int32_t PepperFlashRendererHost::OnGetProxyForURL(
74 ppapi::host::HostMessageContext
* host_context
,
75 const std::string
& url
) {
78 return PP_ERROR_FAILED
;
80 bool result
= content::RenderThread::Get()->ResolveProxy(gurl
, &proxy
);
82 return PP_ERROR_FAILED
;
83 host_context
->reply_msg
= PpapiPluginMsg_Flash_GetProxyForURLReply(proxy
);
87 int32_t PepperFlashRendererHost::OnSetInstanceAlwaysOnTop(
88 ppapi::host::HostMessageContext
* host_context
,
90 content::PepperPluginInstance
* plugin_instance
=
91 host_
->GetPluginInstance(pp_instance());
93 plugin_instance
->SetAlwaysOnTop(on_top
);
94 // Since no reply is sent for this message, it doesn't make sense to return an
99 int32_t PepperFlashRendererHost::OnDrawGlyphs(
100 ppapi::host::HostMessageContext
* host_context
,
101 ppapi::proxy::PPBFlash_DrawGlyphs_Params params
) {
102 if (params
.glyph_indices
.size() != params
.glyph_advances
.size() ||
103 params
.glyph_indices
.empty())
104 return PP_ERROR_FAILED
;
106 // Set up the typeface.
107 int style
= SkTypeface::kNormal
;
108 if (static_cast<PP_BrowserFont_Trusted_Weight
>(params
.font_desc
.weight
) >=
109 PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD
)
110 style
|= SkTypeface::kBold
;
111 if (params
.font_desc
.italic
)
112 style
|= SkTypeface::kItalic
;
113 skia::RefPtr
<SkTypeface
> typeface
= skia::AdoptRef(
114 SkTypeface::CreateFromName(params
.font_desc
.face
.c_str(),
115 static_cast<SkTypeface::Style
>(style
)));
117 return PP_ERROR_FAILED
;
119 EnterResourceNoLock
<PPB_ImageData_API
> enter(
120 params
.image_data
.host_resource(), true);
122 return PP_ERROR_FAILED
;
124 // Set up the canvas.
125 PPB_ImageData_API
* image
= static_cast<PPB_ImageData_API
*>(
127 SkCanvas
* canvas
= image
->GetPlatformCanvas();
128 bool needs_unmapping
= false;
130 needs_unmapping
= true;
132 canvas
= image
->GetPlatformCanvas();
134 return PP_ERROR_FAILED
; // Failure mapping.
137 SkAutoCanvasRestore
acr(canvas
, true);
139 // Clip is applied in pixels before the transform.
141 SkIntToScalar(params
.clip
.point
.x
),
142 SkIntToScalar(params
.clip
.point
.y
),
143 SkIntToScalar(params
.clip
.point
.x
+ params
.clip
.size
.width
),
144 SkIntToScalar(params
.clip
.point
.y
+ params
.clip
.size
.height
)
146 canvas
->clipRect(clip_rect
);
148 // Convert & set the matrix.
150 matrix
.set(SkMatrix::kMScaleX
, SkFloatToScalar(params
.transformation
[0][0]));
151 matrix
.set(SkMatrix::kMSkewX
, SkFloatToScalar(params
.transformation
[0][1]));
152 matrix
.set(SkMatrix::kMTransX
, SkFloatToScalar(params
.transformation
[0][2]));
153 matrix
.set(SkMatrix::kMSkewY
, SkFloatToScalar(params
.transformation
[1][0]));
154 matrix
.set(SkMatrix::kMScaleY
, SkFloatToScalar(params
.transformation
[1][1]));
155 matrix
.set(SkMatrix::kMTransY
, SkFloatToScalar(params
.transformation
[1][2]));
156 matrix
.set(SkMatrix::kMPersp0
, SkFloatToScalar(params
.transformation
[2][0]));
157 matrix
.set(SkMatrix::kMPersp1
, SkFloatToScalar(params
.transformation
[2][1]));
158 matrix
.set(SkMatrix::kMPersp2
, SkFloatToScalar(params
.transformation
[2][2]));
159 canvas
->concat(matrix
);
162 paint
.setColor(params
.color
);
163 paint
.setTextEncoding(SkPaint::kGlyphID_TextEncoding
);
164 paint
.setAntiAlias(true);
165 paint
.setHinting(SkPaint::kFull_Hinting
);
166 paint
.setTextSize(SkIntToScalar(params
.font_desc
.size
));
167 paint
.setTypeface(typeface
.get()); // Takes a ref and manages lifetime.
168 if (params
.allow_subpixel_aa
) {
169 paint
.setSubpixelText(true);
170 paint
.setLCDRenderText(true);
173 SkScalar x
= SkIntToScalar(params
.position
.x
);
174 SkScalar y
= SkIntToScalar(params
.position
.y
);
176 // Build up the skia advances.
177 size_t glyph_count
= params
.glyph_indices
.size();
179 std::vector
<SkPoint
> storage
;
180 storage
.resize(glyph_count
);
181 SkPoint
* sk_positions
= &storage
[0];
182 for (uint32_t i
= 0; i
< glyph_count
; i
++) {
183 sk_positions
[i
].set(x
, y
);
184 x
+= SkFloatToScalar(params
.glyph_advances
[i
].x
);
185 y
+= SkFloatToScalar(params
.glyph_advances
[i
].y
);
188 canvas
->drawPosText(¶ms
.glyph_indices
[0], glyph_count
* 2, sk_positions
,
198 // CAUTION: This code is subtle because Navigate is a sync call which may
199 // cause re-entrancy or cause the instance to be destroyed. If the instance
200 // is destroyed we need to ensure that we respond to all outstanding sync
201 // messages so that the plugin process does not remain blocked.
202 int32_t PepperFlashRendererHost::OnNavigate(
203 ppapi::host::HostMessageContext
* host_context
,
204 const ppapi::URLRequestInfoData
& data
,
205 const std::string
& target
,
206 bool from_user_action
) {
207 // If our PepperPluginInstance is already destroyed, just return a failure.
208 content::PepperPluginInstance
* plugin_instance
=
209 host_
->GetPluginInstance(pp_instance());
210 if (!plugin_instance
)
211 return PP_ERROR_FAILED
;
213 // Navigate may call into Javascript (e.g. with a "javascript:" URL),
214 // or do things like navigate away from the page, either one of which will
215 // need to re-enter into the plugin. It is safe, because it is essentially
216 // equivalent to NPN_GetURL, where Flash would expect re-entrancy.
217 ppapi::proxy::HostDispatcher
* host_dispatcher
=
218 ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
219 host_dispatcher
->set_allow_plugin_reentrancy();
221 // Grab a weak pointer to ourselves on the stack so we can check if we are
223 base::WeakPtr
<PepperFlashRendererHost
> weak_ptr
= weak_factory_
.GetWeakPtr();
224 // Keep track of reply contexts in case we are destroyed during a Navigate
225 // call. Even if we are destroyed, we still need to send these replies to
226 // unblock the plugin process.
227 navigate_replies_
.push_back(host_context
->MakeReplyMessageContext());
228 plugin_instance
->Navigate(data
, target
.c_str(), from_user_action
);
229 // This object might have been destroyed by this point. If it is destroyed
230 // the reply will be sent in the destructor. Otherwise send the reply here.
231 if (weak_ptr
.get()) {
232 SendReply(navigate_replies_
.back(), IPC::Message());
233 navigate_replies_
.pop_back();
236 // Return PP_OK_COMPLETIONPENDING so that no reply is automatically sent.
237 return PP_OK_COMPLETIONPENDING
;
240 int32_t PepperFlashRendererHost::OnIsRectTopmost(
241 ppapi::host::HostMessageContext
* host_context
,
242 const PP_Rect
& rect
) {
243 content::PepperPluginInstance
* plugin_instance
=
244 host_
->GetPluginInstance(pp_instance());
245 if (plugin_instance
&& plugin_instance
->IsRectTopmost(
246 gfx::Rect(rect
.point
.x
, rect
.point
.y
,rect
.size
.width
, rect
.size
.height
)))
248 return PP_ERROR_FAILED
;
251 int32_t PepperFlashRendererHost::OnInvokePrinting(
252 ppapi::host::HostMessageContext
* host_context
) {
253 PPB_PDF_Impl::InvokePrintingForInstance(pp_instance());