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 "chrome/renderer/pepper/pepper_flash_renderer_host.h" 6 7 #include <vector> 8 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" 31 #include "url/gurl.h" 32 33 using ppapi::thunk::EnterResourceNoLock; 34 using ppapi::thunk::PPB_ImageData_API; 35 36 namespace chrome { 37 38 PepperFlashRendererHost::PepperFlashRendererHost( 39 content::RendererPpapiHost* host, 40 PP_Instance instance, 41 PP_Resource resource) 42 : ResourceHost(host->GetPpapiHost(), instance, resource), 43 weak_factory_(this), 44 host_(host) { 45 } 46 47 PepperFlashRendererHost::~PepperFlashRendererHost() { 48 // This object may be destroyed in the middle of a sync message. If that is 49 // the case, make sure we respond to all the pending navigate calls. 50 std::vector<ppapi::host::ReplyMessageContext>::reverse_iterator it; 51 for (it = navigate_replies_.rbegin(); it != navigate_replies_.rend(); ++it) 52 SendReply(*it, IPC::Message()); 53 } 54 55 int32_t PepperFlashRendererHost::OnResourceMessageReceived( 56 const IPC::Message& msg, 57 ppapi::host::HostMessageContext* context) { 58 IPC_BEGIN_MESSAGE_MAP(PepperFlashRendererHost, msg) 59 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_GetProxyForURL, 60 OnGetProxyForURL); 61 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_SetInstanceAlwaysOnTop, 62 OnSetInstanceAlwaysOnTop); 63 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_DrawGlyphs, 64 OnDrawGlyphs); 65 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_Navigate, 66 OnNavigate); 67 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Flash_IsRectTopmost, 68 OnIsRectTopmost); 69 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Flash_InvokePrinting, 70 OnInvokePrinting); 71 IPC_END_MESSAGE_MAP() 72 return PP_ERROR_FAILED; 73 } 74 75 int32_t PepperFlashRendererHost::OnGetProxyForURL( 76 ppapi::host::HostMessageContext* host_context, 77 const std::string& url) { 78 GURL gurl(url); 79 if (!gurl.is_valid()) 80 return PP_ERROR_FAILED; 81 std::string proxy; 82 bool result = content::RenderThread::Get()->ResolveProxy(gurl, &proxy); 83 if (!result) 84 return PP_ERROR_FAILED; 85 host_context->reply_msg = PpapiPluginMsg_Flash_GetProxyForURLReply(proxy); 86 return PP_OK; 87 } 88 89 int32_t PepperFlashRendererHost::OnSetInstanceAlwaysOnTop( 90 ppapi::host::HostMessageContext* host_context, 91 bool on_top) { 92 content::PepperPluginInstance* plugin_instance = 93 host_->GetPluginInstance(pp_instance()); 94 if (plugin_instance) 95 plugin_instance->SetAlwaysOnTop(on_top); 96 // Since no reply is sent for this message, it doesn't make sense to return an 97 // error. 98 return PP_OK; 99 } 100 101 int32_t PepperFlashRendererHost::OnDrawGlyphs( 102 ppapi::host::HostMessageContext* host_context, 103 ppapi::proxy::PPBFlash_DrawGlyphs_Params params) { 104 if (params.glyph_indices.size() != params.glyph_advances.size() || 105 params.glyph_indices.empty()) 106 return PP_ERROR_FAILED; 107 108 // Set up the typeface. 109 int style = SkTypeface::kNormal; 110 if (static_cast<PP_BrowserFont_Trusted_Weight>(params.font_desc.weight) >= 111 PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD) 112 style |= SkTypeface::kBold; 113 if (params.font_desc.italic) 114 style |= SkTypeface::kItalic; 115 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef( 116 SkTypeface::CreateFromName(params.font_desc.face.c_str(), 117 static_cast<SkTypeface::Style>(style))); 118 if (!typeface) 119 return PP_ERROR_FAILED; 120 121 EnterResourceNoLock<PPB_ImageData_API> enter( 122 params.image_data.host_resource(), true); 123 if (enter.failed()) 124 return PP_ERROR_FAILED; 125 126 // Set up the canvas. 127 PPB_ImageData_API* image = static_cast<PPB_ImageData_API*>( 128 enter.object()); 129 SkCanvas* canvas = image->GetPlatformCanvas(); 130 bool needs_unmapping = false; 131 if (!canvas) { 132 needs_unmapping = true; 133 image->Map(); 134 canvas = image->GetPlatformCanvas(); 135 if (!canvas) 136 return PP_ERROR_FAILED; // Failure mapping. 137 } 138 139 SkAutoCanvasRestore acr(canvas, true); 140 141 // Clip is applied in pixels before the transform. 142 SkRect clip_rect = { 143 SkIntToScalar(params.clip.point.x), 144 SkIntToScalar(params.clip.point.y), 145 SkIntToScalar(params.clip.point.x + params.clip.size.width), 146 SkIntToScalar(params.clip.point.y + params.clip.size.height) 147 }; 148 canvas->clipRect(clip_rect); 149 150 // Convert & set the matrix. 151 SkMatrix matrix; 152 matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(params.transformation[0][0])); 153 matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(params.transformation[0][1])); 154 matrix.set(SkMatrix::kMTransX, SkFloatToScalar(params.transformation[0][2])); 155 matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(params.transformation[1][0])); 156 matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(params.transformation[1][1])); 157 matrix.set(SkMatrix::kMTransY, SkFloatToScalar(params.transformation[1][2])); 158 matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(params.transformation[2][0])); 159 matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(params.transformation[2][1])); 160 matrix.set(SkMatrix::kMPersp2, SkFloatToScalar(params.transformation[2][2])); 161 canvas->concat(matrix); 162 163 SkPaint paint; 164 paint.setColor(params.color); 165 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 166 paint.setAntiAlias(true); 167 paint.setHinting(SkPaint::kFull_Hinting); 168 paint.setTextSize(SkIntToScalar(params.font_desc.size)); 169 paint.setTypeface(typeface.get()); // Takes a ref and manages lifetime. 170 if (params.allow_subpixel_aa) { 171 paint.setSubpixelText(true); 172 paint.setLCDRenderText(true); 173 } 174 175 SkScalar x = SkIntToScalar(params.position.x); 176 SkScalar y = SkIntToScalar(params.position.y); 177 178 // Build up the skia advances. 179 size_t glyph_count = params.glyph_indices.size(); 180 if (glyph_count) { 181 std::vector<SkPoint> storage; 182 storage.resize(glyph_count); 183 SkPoint* sk_positions = &storage[0]; 184 for (uint32_t i = 0; i < glyph_count; i++) { 185 sk_positions[i].set(x, y); 186 x += SkFloatToScalar(params.glyph_advances[i].x); 187 y += SkFloatToScalar(params.glyph_advances[i].y); 188 } 189 190 canvas->drawPosText(¶ms.glyph_indices[0], glyph_count * 2, sk_positions, 191 paint); 192 } 193 194 if (needs_unmapping) 195 image->Unmap(); 196 197 return PP_OK; 198 } 199 200 // CAUTION: This code is subtle because Navigate is a sync call which may 201 // cause re-entrancy or cause the instance to be destroyed. If the instance 202 // is destroyed we need to ensure that we respond to all outstanding sync 203 // messages so that the plugin process does not remain blocked. 204 int32_t PepperFlashRendererHost::OnNavigate( 205 ppapi::host::HostMessageContext* host_context, 206 const ppapi::URLRequestInfoData& data, 207 const std::string& target, 208 bool from_user_action) { 209 // If our PepperPluginInstance is already destroyed, just return a failure. 210 content::PepperPluginInstance* plugin_instance = 211 host_->GetPluginInstance(pp_instance()); 212 if (!plugin_instance) 213 return PP_ERROR_FAILED; 214 215 // Navigate may call into Javascript (e.g. with a "javascript:" URL), 216 // or do things like navigate away from the page, either one of which will 217 // need to re-enter into the plugin. It is safe, because it is essentially 218 // equivalent to NPN_GetURL, where Flash would expect re-entrancy. 219 ppapi::proxy::HostDispatcher* host_dispatcher = 220 ppapi::proxy::HostDispatcher::GetForInstance(pp_instance()); 221 host_dispatcher->set_allow_plugin_reentrancy(); 222 223 // Grab a weak pointer to ourselves on the stack so we can check if we are 224 // still alive. 225 base::WeakPtr<PepperFlashRendererHost> weak_ptr = weak_factory_.GetWeakPtr(); 226 // Keep track of reply contexts in case we are destroyed during a Navigate 227 // call. Even if we are destroyed, we still need to send these replies to 228 // unblock the plugin process. 229 navigate_replies_.push_back(host_context->MakeReplyMessageContext()); 230 plugin_instance->Navigate(data, target.c_str(), from_user_action); 231 // This object might have been destroyed by this point. If it is destroyed 232 // the reply will be sent in the destructor. Otherwise send the reply here. 233 if (weak_ptr.get()) { 234 SendReply(navigate_replies_.back(), IPC::Message()); 235 navigate_replies_.pop_back(); 236 } 237 238 // Return PP_OK_COMPLETIONPENDING so that no reply is automatically sent. 239 return PP_OK_COMPLETIONPENDING; 240 } 241 242 int32_t PepperFlashRendererHost::OnIsRectTopmost( 243 ppapi::host::HostMessageContext* host_context, 244 const PP_Rect& rect) { 245 content::PepperPluginInstance* plugin_instance = 246 host_->GetPluginInstance(pp_instance()); 247 if (plugin_instance && plugin_instance->IsRectTopmost( 248 gfx::Rect(rect.point.x, rect.point.y,rect.size.width, rect.size.height))) 249 return PP_OK; 250 return PP_ERROR_FAILED; 251 } 252 253 int32_t PepperFlashRendererHost::OnInvokePrinting( 254 ppapi::host::HostMessageContext* host_context) { 255 PPB_PDF_Impl::InvokePrintingForInstance(pp_instance()); 256 return PP_OK; 257 } 258 259 } // namespace chrome 260