| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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 "webkit/glue/plugins/pepper_plugin_instance.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/metrics/histogram.h" | |
| 9 #if defined(OS_MACOSX) | |
| 10 #include "base/mac_util.h" | |
| 11 #include "base/mac/scoped_cftyperef.h" | |
| 12 #endif | |
| 13 #include "base/scoped_ptr.h" | |
| 14 #include "base/utf_string_conversions.h" | |
| 15 #include "gfx/rect.h" | |
| 16 #if defined(OS_WIN) | |
| 17 #include "gfx/codec/jpeg_codec.h" | |
| 18 #include "gfx/gdi_util.h" | |
| 19 #endif | |
| 20 #include "gfx/skia_util.h" | |
| 21 #include "ppapi/c/dev/ppb_find_dev.h" | |
| 22 #include "ppapi/c/dev/ppb_fullscreen_dev.h" | |
| 23 #include "ppapi/c/dev/ppb_zoom_dev.h" | |
| 24 #include "ppapi/c/dev/ppp_find_dev.h" | |
| 25 #include "ppapi/c/dev/ppp_selection_dev.h" | |
| 26 #include "ppapi/c/dev/ppp_zoom_dev.h" | |
| 27 #include "ppapi/c/pp_input_event.h" | |
| 28 #include "ppapi/c/pp_instance.h" | |
| 29 #include "ppapi/c/pp_rect.h" | |
| 30 #include "ppapi/c/pp_resource.h" | |
| 31 #include "ppapi/c/pp_var.h" | |
| 32 #include "ppapi/c/ppb_core.h" | |
| 33 #include "ppapi/c/ppb_instance.h" | |
| 34 #include "ppapi/c/ppp_instance.h" | |
| 35 #include "printing/native_metafile.h" | |
| 36 #include "printing/units.h" | |
| 37 #include "skia/ext/vector_platform_device.h" | |
| 38 #include "skia/ext/platform_canvas.h" | |
| 39 #include "third_party/WebKit/WebKit/chromium/public/WebBindings.h" | |
| 40 #include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h" | |
| 41 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" | |
| 42 #include "third_party/WebKit/WebKit/chromium/public/WebElement.h" | |
| 43 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" | |
| 44 #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" | |
| 45 #include "third_party/WebKit/WebKit/chromium/public/WebPluginContainer.h" | |
| 46 #include "third_party/WebKit/WebKit/chromium/public/WebRect.h" | |
| 47 #include "third_party/WebKit/WebKit/chromium/public/WebString.h" | |
| 48 #include "third_party/WebKit/WebKit/chromium/public/WebURLRequest.h" | |
| 49 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" | |
| 50 #include "webkit/glue/plugins/pepper_buffer.h" | |
| 51 #include "webkit/glue/plugins/pepper_common.h" | |
| 52 #include "webkit/glue/plugins/pepper_graphics_2d.h" | |
| 53 #include "webkit/glue/plugins/pepper_graphics_3d.h" | |
| 54 #include "webkit/glue/plugins/pepper_event_conversion.h" | |
| 55 #include "webkit/glue/plugins/pepper_fullscreen_container.h" | |
| 56 #include "webkit/glue/plugins/pepper_image_data.h" | |
| 57 #include "webkit/glue/plugins/pepper_plugin_delegate.h" | |
| 58 #include "webkit/glue/plugins/pepper_plugin_module.h" | |
| 59 #include "webkit/glue/plugins/pepper_string.h" | |
| 60 #include "webkit/glue/plugins/pepper_url_loader.h" | |
| 61 #include "webkit/glue/plugins/pepper_var.h" | |
| 62 #include "webkit/glue/plugins/ppp_private.h" | |
| 63 | |
| 64 using WebKit::WebBindings; | |
| 65 using WebKit::WebCanvas; | |
| 66 using WebKit::WebCursorInfo; | |
| 67 using WebKit::WebDocument; | |
| 68 using WebKit::WebFrame; | |
| 69 using WebKit::WebInputEvent; | |
| 70 using WebKit::WebPluginContainer; | |
| 71 using WebKit::WebString; | |
| 72 using WebKit::WebURLRequest; | |
| 73 using WebKit::WebView; | |
| 74 | |
| 75 namespace pepper { | |
| 76 | |
| 77 #if defined(OS_WIN) | |
| 78 // Exported by pdf.dll | |
| 79 typedef bool (*RenderPDFPageToDCProc)( | |
| 80 const unsigned char* pdf_buffer, int buffer_size, int page_number, HDC dc, | |
| 81 int dpi_x, int dpi_y, int bounds_origin_x, int bounds_origin_y, | |
| 82 int bounds_width, int bounds_height, bool fit_to_bounds, | |
| 83 bool stretch_to_bounds, bool keep_aspect_ratio, bool center_in_bounds); | |
| 84 #endif // defined(OS_WIN) | |
| 85 | |
| 86 namespace { | |
| 87 | |
| 88 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \ | |
| 89 COMPILE_ASSERT(int(WebCursorInfo::webkit_name) == int(np_name), \ | |
| 90 mismatching_enums) | |
| 91 | |
| 92 COMPILE_ASSERT_MATCHING_ENUM(TypePointer, PP_CURSORTYPE_POINTER); | |
| 93 COMPILE_ASSERT_MATCHING_ENUM(TypeCross, PP_CURSORTYPE_CROSS); | |
| 94 COMPILE_ASSERT_MATCHING_ENUM(TypeHand, PP_CURSORTYPE_HAND); | |
| 95 COMPILE_ASSERT_MATCHING_ENUM(TypeIBeam, PP_CURSORTYPE_IBEAM); | |
| 96 COMPILE_ASSERT_MATCHING_ENUM(TypeWait, PP_CURSORTYPE_WAIT); | |
| 97 COMPILE_ASSERT_MATCHING_ENUM(TypeHelp, PP_CURSORTYPE_HELP); | |
| 98 COMPILE_ASSERT_MATCHING_ENUM(TypeEastResize, PP_CURSORTYPE_EASTRESIZE); | |
| 99 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthResize, PP_CURSORTYPE_NORTHRESIZE); | |
| 100 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastResize, | |
| 101 PP_CURSORTYPE_NORTHEASTRESIZE); | |
| 102 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestResize, | |
| 103 PP_CURSORTYPE_NORTHWESTRESIZE); | |
| 104 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthResize, PP_CURSORTYPE_SOUTHRESIZE); | |
| 105 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastResize, | |
| 106 PP_CURSORTYPE_SOUTHEASTRESIZE); | |
| 107 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestResize, | |
| 108 PP_CURSORTYPE_SOUTHWESTRESIZE); | |
| 109 COMPILE_ASSERT_MATCHING_ENUM(TypeWestResize, PP_CURSORTYPE_WESTRESIZE); | |
| 110 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthSouthResize, | |
| 111 PP_CURSORTYPE_NORTHSOUTHRESIZE); | |
| 112 COMPILE_ASSERT_MATCHING_ENUM(TypeEastWestResize, PP_CURSORTYPE_EASTWESTRESIZE); | |
| 113 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize, | |
| 114 PP_CURSORTYPE_NORTHEASTSOUTHWESTRESIZE); | |
| 115 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize, | |
| 116 PP_CURSORTYPE_NORTHWESTSOUTHEASTRESIZE); | |
| 117 COMPILE_ASSERT_MATCHING_ENUM(TypeColumnResize, PP_CURSORTYPE_COLUMNRESIZE); | |
| 118 COMPILE_ASSERT_MATCHING_ENUM(TypeRowResize, PP_CURSORTYPE_ROWRESIZE); | |
| 119 COMPILE_ASSERT_MATCHING_ENUM(TypeMiddlePanning, PP_CURSORTYPE_MIDDLEPANNING); | |
| 120 COMPILE_ASSERT_MATCHING_ENUM(TypeEastPanning, PP_CURSORTYPE_EASTPANNING); | |
| 121 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthPanning, PP_CURSORTYPE_NORTHPANNING); | |
| 122 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastPanning, | |
| 123 PP_CURSORTYPE_NORTHEASTPANNING); | |
| 124 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestPanning, | |
| 125 PP_CURSORTYPE_NORTHWESTPANNING); | |
| 126 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthPanning, PP_CURSORTYPE_SOUTHPANNING); | |
| 127 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastPanning, | |
| 128 PP_CURSORTYPE_SOUTHEASTPANNING); | |
| 129 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestPanning, | |
| 130 PP_CURSORTYPE_SOUTHWESTPANNING); | |
| 131 COMPILE_ASSERT_MATCHING_ENUM(TypeWestPanning, PP_CURSORTYPE_WESTPANNING); | |
| 132 COMPILE_ASSERT_MATCHING_ENUM(TypeMove, PP_CURSORTYPE_MOVE); | |
| 133 COMPILE_ASSERT_MATCHING_ENUM(TypeVerticalText, PP_CURSORTYPE_VERTICALTEXT); | |
| 134 COMPILE_ASSERT_MATCHING_ENUM(TypeCell, PP_CURSORTYPE_CELL); | |
| 135 COMPILE_ASSERT_MATCHING_ENUM(TypeContextMenu, PP_CURSORTYPE_CONTEXTMENU); | |
| 136 COMPILE_ASSERT_MATCHING_ENUM(TypeAlias, PP_CURSORTYPE_ALIAS); | |
| 137 COMPILE_ASSERT_MATCHING_ENUM(TypeProgress, PP_CURSORTYPE_PROGRESS); | |
| 138 COMPILE_ASSERT_MATCHING_ENUM(TypeNoDrop, PP_CURSORTYPE_NODROP); | |
| 139 COMPILE_ASSERT_MATCHING_ENUM(TypeCopy, PP_CURSORTYPE_COPY); | |
| 140 COMPILE_ASSERT_MATCHING_ENUM(TypeNone, PP_CURSORTYPE_NONE); | |
| 141 COMPILE_ASSERT_MATCHING_ENUM(TypeNotAllowed, PP_CURSORTYPE_NOTALLOWED); | |
| 142 COMPILE_ASSERT_MATCHING_ENUM(TypeZoomIn, PP_CURSORTYPE_ZOOMIN); | |
| 143 COMPILE_ASSERT_MATCHING_ENUM(TypeZoomOut, PP_CURSORTYPE_ZOOMOUT); | |
| 144 COMPILE_ASSERT_MATCHING_ENUM(TypeCustom, PP_CURSORTYPE_CUSTOM); | |
| 145 | |
| 146 void RectToPPRect(const gfx::Rect& input, PP_Rect* output) { | |
| 147 *output = PP_MakeRectFromXYWH(input.x(), input.y(), | |
| 148 input.width(), input.height()); | |
| 149 } | |
| 150 | |
| 151 PP_Var GetWindowObject(PP_Instance instance_id) { | |
| 152 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 153 if (!instance) | |
| 154 return PP_MakeUndefined(); | |
| 155 return instance->GetWindowObject(); | |
| 156 } | |
| 157 | |
| 158 PP_Var GetOwnerElementObject(PP_Instance instance_id) { | |
| 159 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 160 if (!instance) | |
| 161 return PP_MakeUndefined(); | |
| 162 return instance->GetOwnerElementObject(); | |
| 163 } | |
| 164 | |
| 165 PP_Bool BindGraphics(PP_Instance instance_id, PP_Resource graphics_id) { | |
| 166 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 167 if (!instance) | |
| 168 return PP_FALSE; | |
| 169 return BoolToPPBool(instance->BindGraphics(graphics_id)); | |
| 170 } | |
| 171 | |
| 172 PP_Bool IsFullFrame(PP_Instance instance_id) { | |
| 173 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 174 if (!instance) | |
| 175 return PP_FALSE; | |
| 176 return BoolToPPBool(instance->full_frame()); | |
| 177 } | |
| 178 | |
| 179 PP_Var ExecuteScript(PP_Instance instance_id, | |
| 180 PP_Var script, | |
| 181 PP_Var* exception) { | |
| 182 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 183 if (!instance) | |
| 184 return PP_MakeUndefined(); | |
| 185 return instance->ExecuteScript(script, exception); | |
| 186 } | |
| 187 | |
| 188 const PPB_Instance ppb_instance = { | |
| 189 &GetWindowObject, | |
| 190 &GetOwnerElementObject, | |
| 191 &BindGraphics, | |
| 192 &IsFullFrame, | |
| 193 &ExecuteScript, | |
| 194 }; | |
| 195 | |
| 196 void NumberOfFindResultsChanged(PP_Instance instance_id, | |
| 197 int32_t total, | |
| 198 PP_Bool final_result) { | |
| 199 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 200 if (!instance) | |
| 201 return; | |
| 202 | |
| 203 DCHECK_NE(instance->find_identifier(), -1); | |
| 204 instance->delegate()->NumberOfFindResultsChanged( | |
| 205 instance->find_identifier(), total, PPBoolToBool(final_result)); | |
| 206 } | |
| 207 | |
| 208 void SelectedFindResultChanged(PP_Instance instance_id, | |
| 209 int32_t index) { | |
| 210 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 211 if (!instance) | |
| 212 return; | |
| 213 | |
| 214 DCHECK_NE(instance->find_identifier(), -1); | |
| 215 instance->delegate()->SelectedFindResultChanged( | |
| 216 instance->find_identifier(), index); | |
| 217 } | |
| 218 | |
| 219 const PPB_Find_Dev ppb_find = { | |
| 220 &NumberOfFindResultsChanged, | |
| 221 &SelectedFindResultChanged, | |
| 222 }; | |
| 223 | |
| 224 PP_Bool IsFullscreen(PP_Instance instance_id) { | |
| 225 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 226 if (!instance) | |
| 227 return PP_FALSE; | |
| 228 return BoolToPPBool(instance->IsFullscreen()); | |
| 229 } | |
| 230 | |
| 231 PP_Bool SetFullscreen(PP_Instance instance_id, PP_Bool fullscreen) { | |
| 232 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 233 if (!instance) | |
| 234 return PP_FALSE; | |
| 235 return BoolToPPBool(instance->SetFullscreen(PPBoolToBool(fullscreen))); | |
| 236 } | |
| 237 | |
| 238 const PPB_Fullscreen_Dev ppb_fullscreen = { | |
| 239 &IsFullscreen, | |
| 240 &SetFullscreen, | |
| 241 }; | |
| 242 | |
| 243 void ZoomChanged(PP_Instance instance_id, double factor) { | |
| 244 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 245 if (!instance) | |
| 246 return; | |
| 247 | |
| 248 // We only want to tell the page to change its zoom if the whole page is the | |
| 249 // PDF. If we're in an iframe, then don't do anything. | |
| 250 WebFrame* frame = instance->container()->element().document().frame(); | |
| 251 if (!frame->view()->mainFrame()->document().isPluginDocument()) | |
| 252 return; | |
| 253 | |
| 254 double zoom_level = WebView::zoomFactorToZoomLevel(factor); | |
| 255 // The conversino from zoom level to factor, and back, can introduce rounding | |
| 256 // errors. i.e. WebKit originally tells us 3.0, but by the time we tell the | |
| 257 // plugin and it tells us back, the level becomes 3.000000000004. Need to | |
| 258 // round or else otherwise if the user zooms out, it will go to 3.0 instead of | |
| 259 // 2.0. | |
| 260 int rounded = | |
| 261 static_cast<int>(zoom_level + (zoom_level > 0 ? 0.001 : -0.001)); | |
| 262 if (abs(rounded - zoom_level) < 0.001) | |
| 263 zoom_level = rounded; | |
| 264 instance->container()->zoomLevelChanged(zoom_level); | |
| 265 } | |
| 266 | |
| 267 void ZoomLimitsChanged(PP_Instance instance_id, | |
| 268 double minimum_factor, | |
| 269 double maximium_factor) { | |
| 270 if (minimum_factor > maximium_factor) { | |
| 271 NOTREACHED(); | |
| 272 return; | |
| 273 } | |
| 274 | |
| 275 PluginInstance* instance = ResourceTracker::Get()->GetInstance(instance_id); | |
| 276 if (!instance) | |
| 277 return; | |
| 278 instance->delegate()->ZoomLimitsChanged(minimum_factor, maximium_factor); | |
| 279 } | |
| 280 | |
| 281 const PPB_Zoom_Dev ppb_zoom = { | |
| 282 &ZoomChanged, | |
| 283 &ZoomLimitsChanged | |
| 284 }; | |
| 285 | |
| 286 } // namespace | |
| 287 | |
| 288 PluginInstance::PluginInstance(PluginDelegate* delegate, | |
| 289 PluginModule* module, | |
| 290 const PPP_Instance* instance_interface) | |
| 291 : delegate_(delegate), | |
| 292 module_(module), | |
| 293 instance_interface_(instance_interface), | |
| 294 pp_instance_(0), | |
| 295 container_(NULL), | |
| 296 full_frame_(false), | |
| 297 has_webkit_focus_(false), | |
| 298 has_content_area_focus_(false), | |
| 299 find_identifier_(-1), | |
| 300 plugin_find_interface_(NULL), | |
| 301 plugin_private_interface_(NULL), | |
| 302 plugin_selection_interface_(NULL), | |
| 303 plugin_zoom_interface_(NULL), | |
| 304 #if defined (OS_LINUX) | |
| 305 num_pages_(0), | |
| 306 pdf_output_done_(false), | |
| 307 #endif // defined (OS_LINUX) | |
| 308 plugin_print_interface_(NULL), | |
| 309 plugin_graphics_3d_interface_(NULL), | |
| 310 always_on_top_(false), | |
| 311 fullscreen_container_(NULL) { | |
| 312 pp_instance_ = ResourceTracker::Get()->AddInstance(this); | |
| 313 | |
| 314 memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); | |
| 315 DCHECK(delegate); | |
| 316 module_->InstanceCreated(this); | |
| 317 delegate_->InstanceCreated(this); | |
| 318 } | |
| 319 | |
| 320 PluginInstance::~PluginInstance() { | |
| 321 FOR_EACH_OBSERVER(Observer, observers_, InstanceDestroyed(this)); | |
| 322 | |
| 323 delegate_->InstanceDeleted(this); | |
| 324 module_->InstanceDeleted(this); | |
| 325 | |
| 326 ResourceTracker::Get()->InstanceDeleted(pp_instance_); | |
| 327 } | |
| 328 | |
| 329 // static | |
| 330 const PPB_Instance* PluginInstance::GetInterface() { | |
| 331 return &ppb_instance; | |
| 332 } | |
| 333 | |
| 334 // static | |
| 335 const PPB_Find_Dev* PluginInstance::GetFindInterface() { | |
| 336 return &ppb_find; | |
| 337 } | |
| 338 | |
| 339 // static | |
| 340 const PPB_Fullscreen_Dev* PluginInstance::GetFullscreenInterface() { | |
| 341 return &ppb_fullscreen; | |
| 342 } | |
| 343 | |
| 344 // static | |
| 345 const PPB_Zoom_Dev* PluginInstance::GetZoomInterface() { | |
| 346 return &ppb_zoom; | |
| 347 } | |
| 348 | |
| 349 void PluginInstance::AddObserver(Observer* observer) { | |
| 350 observers_.AddObserver(observer); | |
| 351 } | |
| 352 | |
| 353 void PluginInstance::RemoveObserver(Observer* observer) { | |
| 354 observers_.RemoveObserver(observer); | |
| 355 } | |
| 356 | |
| 357 void PluginInstance::Paint(WebCanvas* canvas, | |
| 358 const gfx::Rect& plugin_rect, | |
| 359 const gfx::Rect& paint_rect) { | |
| 360 if (bound_graphics_2d()) | |
| 361 bound_graphics_2d()->Paint(canvas, plugin_rect, paint_rect); | |
| 362 } | |
| 363 | |
| 364 void PluginInstance::InvalidateRect(const gfx::Rect& rect) { | |
| 365 if (fullscreen_container_) { | |
| 366 if (rect.IsEmpty()) | |
| 367 fullscreen_container_->Invalidate(); | |
| 368 else | |
| 369 fullscreen_container_->InvalidateRect(rect); | |
| 370 } else { | |
| 371 if (!container_ || position_.IsEmpty()) | |
| 372 return; // Nothing to do. | |
| 373 if (rect.IsEmpty()) | |
| 374 container_->invalidate(); | |
| 375 else | |
| 376 container_->invalidateRect(rect); | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 void PluginInstance::ScrollRect(int dx, int dy, const gfx::Rect& rect) { | |
| 381 if (fullscreen_container_) { | |
| 382 fullscreen_container_->ScrollRect(dx, dy, rect); | |
| 383 } else { | |
| 384 if (full_frame_) { | |
| 385 container_->scrollRect(dx, dy, rect); | |
| 386 } else { | |
| 387 // Can't do optimized scrolling since there could be other elements on top | |
| 388 // of us. | |
| 389 InvalidateRect(rect); | |
| 390 } | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 unsigned PluginInstance::GetBackingTextureId() { | |
| 395 if (!bound_graphics_3d()) | |
| 396 return 0; | |
| 397 | |
| 398 return bound_graphics_3d()->GetBackingTextureId(); | |
| 399 } | |
| 400 | |
| 401 void PluginInstance::CommitBackingTexture() { | |
| 402 container_->commitBackingTexture(); | |
| 403 } | |
| 404 | |
| 405 PP_Var PluginInstance::GetWindowObject() { | |
| 406 if (!container_) | |
| 407 return PP_MakeUndefined(); | |
| 408 | |
| 409 WebFrame* frame = container_->element().document().frame(); | |
| 410 if (!frame) | |
| 411 return PP_MakeUndefined(); | |
| 412 | |
| 413 return ObjectVar::NPObjectToPPVar(module(), frame->windowObject()); | |
| 414 } | |
| 415 | |
| 416 PP_Var PluginInstance::GetOwnerElementObject() { | |
| 417 if (!container_) | |
| 418 return PP_MakeUndefined(); | |
| 419 return ObjectVar::NPObjectToPPVar(module(), | |
| 420 container_->scriptableObjectForElement()); | |
| 421 } | |
| 422 | |
| 423 bool PluginInstance::BindGraphics(PP_Resource graphics_id) { | |
| 424 if (!graphics_id) { | |
| 425 // Special-case clearing the current device. | |
| 426 if (bound_graphics_.get()) { | |
| 427 if (bound_graphics_2d()) { | |
| 428 bound_graphics_2d()->BindToInstance(NULL); | |
| 429 } else if (bound_graphics_.get()) { | |
| 430 bound_graphics_3d()->SetSwapBuffersCallback(NULL); | |
| 431 bound_graphics_3d()->BindToInstance(NULL); | |
| 432 } | |
| 433 InvalidateRect(gfx::Rect()); | |
| 434 } | |
| 435 bound_graphics_ = NULL; | |
| 436 return true; | |
| 437 } | |
| 438 | |
| 439 scoped_refptr<Graphics2D> graphics_2d = | |
| 440 Resource::GetAs<Graphics2D>(graphics_id); | |
| 441 scoped_refptr<Graphics3D> graphics_3d = | |
| 442 Resource::GetAs<Graphics3D>(graphics_id); | |
| 443 | |
| 444 if (graphics_2d) { | |
| 445 if (!graphics_2d->BindToInstance(this)) | |
| 446 return false; // Can't bind to more than one instance. | |
| 447 | |
| 448 // See http://crbug.com/49403: this can be further optimized by keeping the | |
| 449 // old device around and painting from it. | |
| 450 if (bound_graphics_2d()) { | |
| 451 // Start the new image with the content of the old image until the plugin | |
| 452 // repaints. | |
| 453 const SkBitmap* old_backing_bitmap = | |
| 454 bound_graphics_2d()->image_data()->GetMappedBitmap(); | |
| 455 SkRect old_size = SkRect::MakeWH( | |
| 456 SkScalar(static_cast<float>(old_backing_bitmap->width())), | |
| 457 SkScalar(static_cast<float>(old_backing_bitmap->height()))); | |
| 458 | |
| 459 SkCanvas canvas(*graphics_2d->image_data()->GetMappedBitmap()); | |
| 460 canvas.drawBitmap(*old_backing_bitmap, 0, 0); | |
| 461 | |
| 462 // Fill in any extra space with white. | |
| 463 canvas.clipRect(old_size, SkRegion::kDifference_Op); | |
| 464 canvas.drawARGB(255, 255, 255, 255); | |
| 465 } | |
| 466 | |
| 467 bound_graphics_ = graphics_2d; | |
| 468 // BindToInstance will have invalidated the plugin if necessary. | |
| 469 } else if (graphics_3d) { | |
| 470 if (!graphics_3d->BindToInstance(this)) | |
| 471 return false; | |
| 472 | |
| 473 bound_graphics_ = graphics_3d; | |
| 474 bound_graphics_3d()->SetSwapBuffersCallback( | |
| 475 NewCallback(this, &PluginInstance::CommitBackingTexture)); | |
| 476 } | |
| 477 | |
| 478 return true; | |
| 479 } | |
| 480 | |
| 481 bool PluginInstance::SetCursor(PP_CursorType_Dev type) { | |
| 482 cursor_.reset(new WebCursorInfo(static_cast<WebCursorInfo::Type>(type))); | |
| 483 return true; | |
| 484 } | |
| 485 | |
| 486 PP_Var PluginInstance::ExecuteScript(PP_Var script, PP_Var* exception) { | |
| 487 TryCatch try_catch(module(), exception); | |
| 488 if (try_catch.has_exception()) | |
| 489 return PP_MakeUndefined(); | |
| 490 | |
| 491 // Convert the script into an inconvenient NPString object. | |
| 492 scoped_refptr<StringVar> script_string(StringVar::FromPPVar(script)); | |
| 493 if (!script_string) { | |
| 494 try_catch.SetException("Script param to ExecuteScript must be a string."); | |
| 495 return PP_MakeUndefined(); | |
| 496 } | |
| 497 NPString np_script; | |
| 498 np_script.UTF8Characters = script_string->value().c_str(); | |
| 499 np_script.UTF8Length = script_string->value().length(); | |
| 500 | |
| 501 // Get the current frame to pass to the evaluate function. | |
| 502 WebFrame* frame = container_->element().document().frame(); | |
| 503 if (!frame) { | |
| 504 try_catch.SetException("No frame to execute script in."); | |
| 505 return PP_MakeUndefined(); | |
| 506 } | |
| 507 | |
| 508 NPVariant result; | |
| 509 bool ok = WebBindings::evaluate(NULL, frame->windowObject(), &np_script, | |
| 510 &result); | |
| 511 if (!ok) { | |
| 512 // TODO(brettw) bug 54011: The TryCatch isn't working properly and | |
| 513 // doesn't actually catch this exception. | |
| 514 try_catch.SetException("Exception caught"); | |
| 515 WebBindings::releaseVariantValue(&result); | |
| 516 return PP_MakeUndefined(); | |
| 517 } | |
| 518 | |
| 519 PP_Var ret = Var::NPVariantToPPVar(module_, &result); | |
| 520 WebBindings::releaseVariantValue(&result); | |
| 521 return ret; | |
| 522 } | |
| 523 | |
| 524 void PluginInstance::Delete() { | |
| 525 instance_interface_->DidDestroy(pp_instance()); | |
| 526 | |
| 527 if (fullscreen_container_) { | |
| 528 fullscreen_container_->Destroy(); | |
| 529 fullscreen_container_ = NULL; | |
| 530 } | |
| 531 container_ = NULL; | |
| 532 } | |
| 533 | |
| 534 bool PluginInstance::Initialize(WebPluginContainer* container, | |
| 535 const std::vector<std::string>& arg_names, | |
| 536 const std::vector<std::string>& arg_values, | |
| 537 bool full_frame) { | |
| 538 container_ = container; | |
| 539 full_frame_ = full_frame; | |
| 540 | |
| 541 size_t argc = 0; | |
| 542 scoped_array<const char*> argn(new const char*[arg_names.size()]); | |
| 543 scoped_array<const char*> argv(new const char*[arg_names.size()]); | |
| 544 for (size_t i = 0; i < arg_names.size(); ++i) { | |
| 545 argn[argc] = arg_names[i].c_str(); | |
| 546 argv[argc] = arg_values[i].c_str(); | |
| 547 argc++; | |
| 548 } | |
| 549 | |
| 550 return PPBoolToBool(instance_interface_->DidCreate(pp_instance(), | |
| 551 argc, | |
| 552 argn.get(), | |
| 553 argv.get())); | |
| 554 } | |
| 555 | |
| 556 bool PluginInstance::HandleDocumentLoad(URLLoader* loader) { | |
| 557 Resource::ScopedResourceId resource(loader); | |
| 558 return PPBoolToBool(instance_interface_->HandleDocumentLoad(pp_instance(), | |
| 559 resource.id)); | |
| 560 } | |
| 561 | |
| 562 bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent& event, | |
| 563 WebCursorInfo* cursor_info) { | |
| 564 std::vector<PP_InputEvent> pp_events; | |
| 565 CreatePPEvent(event, &pp_events); | |
| 566 | |
| 567 // Each input event may generate more than one PP_InputEvent. | |
| 568 bool rv = false; | |
| 569 for (size_t i = 0; i < pp_events.size(); i++) { | |
| 570 rv |= PPBoolToBool(instance_interface_->HandleInputEvent(pp_instance(), | |
| 571 &pp_events[i])); | |
| 572 } | |
| 573 | |
| 574 if (cursor_.get()) | |
| 575 *cursor_info = *cursor_; | |
| 576 return rv; | |
| 577 } | |
| 578 | |
| 579 PP_Var PluginInstance::GetInstanceObject() { | |
| 580 return instance_interface_->GetInstanceObject(pp_instance()); | |
| 581 } | |
| 582 | |
| 583 void PluginInstance::ViewChanged(const gfx::Rect& position, | |
| 584 const gfx::Rect& clip) { | |
| 585 if (position.size() != position_.size() && bound_graphics_3d()) { | |
| 586 // TODO(apatrick): This is a hack to force the back buffer to resize. | |
| 587 // It is obviously wrong to call SwapBuffers when a partial frame has | |
| 588 // potentially been rendered. Plan is to embed resize commands in the | |
| 589 // command buffer just before ViewChanged is called. | |
| 590 bound_graphics_3d()->ResizeBackingTexture(position.size()); | |
| 591 bound_graphics_3d()->SwapBuffers(); | |
| 592 } | |
| 593 | |
| 594 position_ = position; | |
| 595 | |
| 596 if (clip.IsEmpty()) { | |
| 597 // WebKit can give weird (x,y) positions for empty clip rects (since the | |
| 598 // position technically doesn't matter). But we want to make these | |
| 599 // consistent since this is given to the plugin, so force everything to 0 | |
| 600 // in the "everything is clipped" case. | |
| 601 clip_ = gfx::Rect(); | |
| 602 } else { | |
| 603 clip_ = clip; | |
| 604 } | |
| 605 | |
| 606 PP_Rect pp_position, pp_clip; | |
| 607 RectToPPRect(position_, &pp_position); | |
| 608 RectToPPRect(clip_, &pp_clip); | |
| 609 instance_interface_->DidChangeView(pp_instance(), &pp_position, &pp_clip); | |
| 610 } | |
| 611 | |
| 612 void PluginInstance::SetWebKitFocus(bool has_focus) { | |
| 613 if (has_webkit_focus_ == has_focus) | |
| 614 return; | |
| 615 | |
| 616 bool old_plugin_focus = PluginHasFocus(); | |
| 617 has_webkit_focus_ = has_focus; | |
| 618 if (PluginHasFocus() != old_plugin_focus) { | |
| 619 instance_interface_->DidChangeFocus(pp_instance(), | |
| 620 BoolToPPBool(PluginHasFocus())); | |
| 621 } | |
| 622 } | |
| 623 | |
| 624 void PluginInstance::SetContentAreaFocus(bool has_focus) { | |
| 625 if (has_content_area_focus_ == has_focus) | |
| 626 return; | |
| 627 | |
| 628 bool old_plugin_focus = PluginHasFocus(); | |
| 629 has_content_area_focus_ = has_focus; | |
| 630 if (PluginHasFocus() != old_plugin_focus) { | |
| 631 instance_interface_->DidChangeFocus(pp_instance(), | |
| 632 BoolToPPBool(PluginHasFocus())); | |
| 633 } | |
| 634 } | |
| 635 | |
| 636 void PluginInstance::ViewInitiatedPaint() { | |
| 637 if (bound_graphics_2d()) | |
| 638 bound_graphics_2d()->ViewInitiatedPaint(); | |
| 639 } | |
| 640 | |
| 641 void PluginInstance::ViewFlushedPaint() { | |
| 642 if (bound_graphics_2d()) | |
| 643 bound_graphics_2d()->ViewFlushedPaint(); | |
| 644 } | |
| 645 | |
| 646 bool PluginInstance::GetBitmapForOptimizedPluginPaint( | |
| 647 const gfx::Rect& paint_bounds, | |
| 648 TransportDIB** dib, | |
| 649 gfx::Rect* location, | |
| 650 gfx::Rect* clip) { | |
| 651 if (!always_on_top_) | |
| 652 return false; | |
| 653 if (!bound_graphics_2d() || !bound_graphics_2d()->is_always_opaque()) | |
| 654 return false; | |
| 655 | |
| 656 // We specifically want to compare against the area covered by the backing | |
| 657 // store when seeing if we cover the given paint bounds, since the backing | |
| 658 // store could be smaller than the declared plugin area. | |
| 659 ImageData* image_data = bound_graphics_2d()->image_data(); | |
| 660 gfx::Rect plugin_backing_store_rect(position_.origin(), | |
| 661 gfx::Size(image_data->width(), | |
| 662 image_data->height())); | |
| 663 gfx::Rect clip_page(clip_); | |
| 664 clip_page.Offset(position_.origin()); | |
| 665 gfx::Rect plugin_paint_rect = plugin_backing_store_rect.Intersect(clip_page); | |
| 666 if (!plugin_paint_rect.Contains(paint_bounds)) | |
| 667 return false; | |
| 668 | |
| 669 *dib = image_data->platform_image()->GetTransportDIB(); | |
| 670 *location = plugin_backing_store_rect; | |
| 671 *clip = clip_page; | |
| 672 return true; | |
| 673 } | |
| 674 | |
| 675 string16 PluginInstance::GetSelectedText(bool html) { | |
| 676 if (!LoadSelectionInterface()) | |
| 677 return string16(); | |
| 678 | |
| 679 PP_Var rv = plugin_selection_interface_->GetSelectedText(pp_instance(), | |
| 680 BoolToPPBool(html)); | |
| 681 scoped_refptr<StringVar> string(StringVar::FromPPVar(rv)); | |
| 682 Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us. | |
| 683 if (!string) | |
| 684 return string16(); | |
| 685 return UTF8ToUTF16(string->value()); | |
| 686 } | |
| 687 | |
| 688 string16 PluginInstance::GetLinkAtPosition(const gfx::Point& point) { | |
| 689 if (!LoadPrivateInterface()) | |
| 690 return string16(); | |
| 691 | |
| 692 PP_Point p; | |
| 693 p.x = point.x(); | |
| 694 p.y = point.y(); | |
| 695 PP_Var rv = plugin_private_interface_->GetLinkAtPosition(pp_instance(), p); | |
| 696 scoped_refptr<StringVar> string(StringVar::FromPPVar(rv)); | |
| 697 Var::PluginReleasePPVar(rv); // Release the ref the plugin transfered to us. | |
| 698 if (!string) | |
| 699 return string16(); | |
| 700 return UTF8ToUTF16(string->value()); | |
| 701 } | |
| 702 | |
| 703 void PluginInstance::Zoom(double factor, bool text_only) { | |
| 704 if (!LoadZoomInterface()) | |
| 705 return; | |
| 706 plugin_zoom_interface_->Zoom(pp_instance(), factor, BoolToPPBool(text_only)); | |
| 707 } | |
| 708 | |
| 709 bool PluginInstance::StartFind(const string16& search_text, | |
| 710 bool case_sensitive, | |
| 711 int identifier) { | |
| 712 if (!LoadFindInterface()) | |
| 713 return false; | |
| 714 find_identifier_ = identifier; | |
| 715 return PPBoolToBool( | |
| 716 plugin_find_interface_->StartFind( | |
| 717 pp_instance(), | |
| 718 UTF16ToUTF8(search_text.c_str()).c_str(), | |
| 719 BoolToPPBool(case_sensitive))); | |
| 720 } | |
| 721 | |
| 722 void PluginInstance::SelectFindResult(bool forward) { | |
| 723 if (LoadFindInterface()) | |
| 724 plugin_find_interface_->SelectFindResult(pp_instance(), | |
| 725 BoolToPPBool(forward)); | |
| 726 } | |
| 727 | |
| 728 void PluginInstance::StopFind() { | |
| 729 if (!LoadFindInterface()) | |
| 730 return; | |
| 731 find_identifier_ = -1; | |
| 732 plugin_find_interface_->StopFind(pp_instance()); | |
| 733 } | |
| 734 | |
| 735 bool PluginInstance::LoadFindInterface() { | |
| 736 if (!plugin_find_interface_) { | |
| 737 plugin_find_interface_ = | |
| 738 reinterpret_cast<const PPP_Find_Dev*>(module_->GetPluginInterface( | |
| 739 PPP_FIND_DEV_INTERFACE)); | |
| 740 } | |
| 741 | |
| 742 return !!plugin_find_interface_; | |
| 743 } | |
| 744 | |
| 745 bool PluginInstance::LoadPrivateInterface() { | |
| 746 if (!plugin_private_interface_) { | |
| 747 plugin_private_interface_ = | |
| 748 reinterpret_cast<const PPP_Private*>(module_->GetPluginInterface( | |
| 749 PPP_PRIVATE_INTERFACE)); | |
| 750 } | |
| 751 | |
| 752 return !!plugin_private_interface_; | |
| 753 } | |
| 754 | |
| 755 bool PluginInstance::LoadSelectionInterface() { | |
| 756 if (!plugin_selection_interface_) { | |
| 757 plugin_selection_interface_ = | |
| 758 reinterpret_cast<const PPP_Selection_Dev*>(module_->GetPluginInterface( | |
| 759 PPP_SELECTION_DEV_INTERFACE)); | |
| 760 } | |
| 761 | |
| 762 return !!plugin_selection_interface_; | |
| 763 } | |
| 764 | |
| 765 bool PluginInstance::LoadZoomInterface() { | |
| 766 if (!plugin_zoom_interface_) { | |
| 767 plugin_zoom_interface_ = | |
| 768 reinterpret_cast<const PPP_Zoom_Dev*>(module_->GetPluginInterface( | |
| 769 PPP_ZOOM_DEV_INTERFACE)); | |
| 770 } | |
| 771 | |
| 772 return !!plugin_zoom_interface_; | |
| 773 } | |
| 774 | |
| 775 bool PluginInstance::PluginHasFocus() const { | |
| 776 return has_webkit_focus_ && has_content_area_focus_; | |
| 777 } | |
| 778 | |
| 779 bool PluginInstance::GetPreferredPrintOutputFormat( | |
| 780 PP_PrintOutputFormat_Dev* format) { | |
| 781 if (!plugin_print_interface_) { | |
| 782 plugin_print_interface_ = | |
| 783 reinterpret_cast<const PPP_Printing_Dev*>(module_->GetPluginInterface( | |
| 784 PPP_PRINTING_DEV_INTERFACE)); | |
| 785 } | |
| 786 if (!plugin_print_interface_) | |
| 787 return false; | |
| 788 uint32_t format_count = 0; | |
| 789 PP_PrintOutputFormat_Dev* supported_formats = | |
| 790 plugin_print_interface_->QuerySupportedFormats(pp_instance(), | |
| 791 &format_count); | |
| 792 if (!supported_formats) | |
| 793 return false; | |
| 794 | |
| 795 bool found_supported_format = false; | |
| 796 for (uint32_t index = 0; index < format_count; index++) { | |
| 797 if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_PDF) { | |
| 798 // If we found PDF, we are done. | |
| 799 found_supported_format = true; | |
| 800 *format = PP_PRINTOUTPUTFORMAT_PDF; | |
| 801 break; | |
| 802 } else if (supported_formats[index] == PP_PRINTOUTPUTFORMAT_RASTER) { | |
| 803 // We found raster. Keep looking. | |
| 804 found_supported_format = true; | |
| 805 *format = PP_PRINTOUTPUTFORMAT_RASTER; | |
| 806 } | |
| 807 } | |
| 808 PluginModule::GetCore()->MemFree(supported_formats); | |
| 809 return found_supported_format; | |
| 810 } | |
| 811 | |
| 812 bool PluginInstance::SupportsPrintInterface() { | |
| 813 PP_PrintOutputFormat_Dev format; | |
| 814 return GetPreferredPrintOutputFormat(&format); | |
| 815 } | |
| 816 | |
| 817 int PluginInstance::PrintBegin(const gfx::Rect& printable_area, | |
| 818 int printer_dpi) { | |
| 819 PP_PrintOutputFormat_Dev format; | |
| 820 if (!GetPreferredPrintOutputFormat(&format)) { | |
| 821 // PrintBegin should not have been called since SupportsPrintInterface | |
| 822 // would have returned false; | |
| 823 NOTREACHED(); | |
| 824 return 0; | |
| 825 } | |
| 826 | |
| 827 PP_PrintSettings_Dev print_settings; | |
| 828 RectToPPRect(printable_area, &print_settings.printable_area); | |
| 829 print_settings.dpi = printer_dpi; | |
| 830 print_settings.orientation = PP_PRINTORIENTATION_NORMAL; | |
| 831 print_settings.grayscale = PP_FALSE; | |
| 832 print_settings.format = format; | |
| 833 int num_pages = plugin_print_interface_->Begin(pp_instance(), | |
| 834 &print_settings); | |
| 835 if (!num_pages) | |
| 836 return 0; | |
| 837 current_print_settings_ = print_settings; | |
| 838 #if defined (OS_LINUX) | |
| 839 num_pages_ = num_pages; | |
| 840 pdf_output_done_ = false; | |
| 841 #endif // (OS_LINUX) | |
| 842 return num_pages; | |
| 843 } | |
| 844 | |
| 845 bool PluginInstance::PrintPage(int page_number, WebKit::WebCanvas* canvas) { | |
| 846 DCHECK(plugin_print_interface_); | |
| 847 PP_PrintPageNumberRange_Dev page_range; | |
| 848 #if defined(OS_LINUX) | |
| 849 if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF) { | |
| 850 // On Linux we will try and output all pages as PDF in the first call to | |
| 851 // PrintPage. This is a temporary hack. | |
| 852 // TODO(sanjeevr): Remove this hack and fix this by changing the print | |
| 853 // interfaces for WebFrame and WebPlugin. | |
| 854 if (page_number != 0) | |
| 855 return pdf_output_done_; | |
| 856 page_range.first_page_number = 0; | |
| 857 page_range.last_page_number = num_pages_ - 1; | |
| 858 } | |
| 859 #else // defined(OS_LINUX) | |
| 860 page_range.first_page_number = page_range.last_page_number = page_number; | |
| 861 #endif // defined(OS_LINUX) | |
| 862 | |
| 863 PP_Resource print_output = | |
| 864 plugin_print_interface_->PrintPages(pp_instance(), &page_range, 1); | |
| 865 | |
| 866 if (!print_output) | |
| 867 return false; | |
| 868 | |
| 869 bool ret = false; | |
| 870 | |
| 871 if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_PDF) | |
| 872 ret = PrintPDFOutput(print_output, canvas); | |
| 873 else if (current_print_settings_.format == PP_PRINTOUTPUTFORMAT_RASTER) | |
| 874 ret = PrintRasterOutput(print_output, canvas); | |
| 875 | |
| 876 // Now we need to release the print output resource. | |
| 877 PluginModule::GetCore()->ReleaseResource(print_output); | |
| 878 | |
| 879 return ret; | |
| 880 } | |
| 881 | |
| 882 void PluginInstance::PrintEnd() { | |
| 883 DCHECK(plugin_print_interface_); | |
| 884 if (plugin_print_interface_) | |
| 885 plugin_print_interface_->End(pp_instance()); | |
| 886 memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); | |
| 887 #if defined(OS_MACOSX) | |
| 888 last_printed_page_ = NULL; | |
| 889 #elif defined(OS_LINUX) | |
| 890 num_pages_ = 0; | |
| 891 pdf_output_done_ = false; | |
| 892 #endif // defined(OS_LINUX) | |
| 893 } | |
| 894 | |
| 895 bool PluginInstance::IsFullscreen() { | |
| 896 return fullscreen_container_ != NULL; | |
| 897 } | |
| 898 | |
| 899 bool PluginInstance::SetFullscreen(bool fullscreen) { | |
| 900 bool is_fullscreen = (fullscreen_container_ != NULL); | |
| 901 if (fullscreen == is_fullscreen) | |
| 902 return true; | |
| 903 VLOG(1) << "Setting fullscreen to " << (fullscreen ? "on" : "off"); | |
| 904 if (fullscreen) { | |
| 905 fullscreen_container_ = delegate_->CreateFullscreenContainer(this); | |
| 906 } else { | |
| 907 fullscreen_container_->Destroy(); | |
| 908 fullscreen_container_ = NULL; | |
| 909 // TODO(piman): currently the fullscreen container resizes the plugin to the | |
| 910 // fullscreen size so we need to reset the size here. Eventually it will | |
| 911 // transparently scale and this won't be necessary. | |
| 912 if (container_) { | |
| 913 container_->reportGeometry(); | |
| 914 container_->invalidate(); | |
| 915 } | |
| 916 } | |
| 917 return true; | |
| 918 } | |
| 919 | |
| 920 bool PluginInstance::NavigateToURL(const char* url, const char* target) { | |
| 921 if (!url || !target || !container_) | |
| 922 return false; | |
| 923 | |
| 924 WebDocument document = container_->element().document(); | |
| 925 GURL complete_url = document.completeURL(WebString::fromUTF8(url)); | |
| 926 // Don't try to deal with the security issues of javascript. | |
| 927 if (complete_url.SchemeIs("javascript")) | |
| 928 return false; | |
| 929 | |
| 930 WebURLRequest request(complete_url); | |
| 931 document.frame()->setReferrerForRequest(request, GURL()); | |
| 932 request.setHTTPMethod(WebString::fromUTF8("GET")); | |
| 933 request.setFirstPartyForCookies(document.firstPartyForCookies()); | |
| 934 | |
| 935 WebString target_str = WebString::fromUTF8(target); | |
| 936 container_->loadFrameRequest(request, target_str, false, NULL); | |
| 937 return true; | |
| 938 } | |
| 939 | |
| 940 bool PluginInstance::PrintPDFOutput(PP_Resource print_output, | |
| 941 WebKit::WebCanvas* canvas) { | |
| 942 scoped_refptr<Buffer> buffer(Resource::GetAs<Buffer>(print_output)); | |
| 943 if (!buffer.get() || !buffer->is_mapped() || !buffer->size()) { | |
| 944 NOTREACHED(); | |
| 945 return false; | |
| 946 } | |
| 947 #if defined(OS_WIN) | |
| 948 // For Windows, we need the PDF DLL to render the output PDF to a DC. | |
| 949 HMODULE pdf_module = GetModuleHandle(L"pdf.dll"); | |
| 950 if (!pdf_module) | |
| 951 return false; | |
| 952 RenderPDFPageToDCProc render_proc = | |
| 953 reinterpret_cast<RenderPDFPageToDCProc>( | |
| 954 GetProcAddress(pdf_module, "RenderPDFPageToDC")); | |
| 955 if (!render_proc) | |
| 956 return false; | |
| 957 #endif // defined(OS_WIN) | |
| 958 | |
| 959 bool ret = false; | |
| 960 #if defined(OS_LINUX) | |
| 961 // On Linux we need to get the backing PdfPsMetafile and write the bits | |
| 962 // directly. | |
| 963 cairo_t* context = canvas->beginPlatformPaint(); | |
| 964 printing::NativeMetafile* metafile = | |
| 965 printing::NativeMetafile::FromCairoContext(context); | |
| 966 DCHECK(metafile); | |
| 967 if (metafile) { | |
| 968 ret = metafile->SetRawData(buffer->mapped_buffer(), buffer->size()); | |
| 969 if (ret) | |
| 970 pdf_output_done_ = true; | |
| 971 } | |
| 972 canvas->endPlatformPaint(); | |
| 973 #elif defined(OS_MACOSX) | |
| 974 printing::NativeMetafile metafile; | |
| 975 // Create a PDF metafile and render from there into the passed in context. | |
| 976 if (metafile.Init(buffer->mapped_buffer(), buffer->size())) { | |
| 977 // Flip the transform. | |
| 978 CGContextSaveGState(canvas); | |
| 979 CGContextTranslateCTM(canvas, 0, | |
| 980 current_print_settings_.printable_area.size.height); | |
| 981 CGContextScaleCTM(canvas, 1.0, -1.0); | |
| 982 CGRect page_rect; | |
| 983 page_rect.origin.x = current_print_settings_.printable_area.point.x; | |
| 984 page_rect.origin.y = current_print_settings_.printable_area.point.y; | |
| 985 page_rect.size.width = current_print_settings_.printable_area.size.width; | |
| 986 page_rect.size.height = current_print_settings_.printable_area.size.height; | |
| 987 | |
| 988 ret = metafile.RenderPage(1, canvas, page_rect, true, false, true, true); | |
| 989 CGContextRestoreGState(canvas); | |
| 990 } | |
| 991 #elif defined(OS_WIN) | |
| 992 // On Windows, we now need to render the PDF to the DC that backs the | |
| 993 // supplied canvas. | |
| 994 skia::VectorPlatformDevice& device = | |
| 995 static_cast<skia::VectorPlatformDevice&>( | |
| 996 canvas->getTopPlatformDevice()); | |
| 997 HDC dc = device.getBitmapDC(); | |
| 998 gfx::Size size_in_pixels; | |
| 999 size_in_pixels.set_width( | |
| 1000 printing::ConvertUnit(current_print_settings_.printable_area.size.width, | |
| 1001 static_cast<int>(printing::kPointsPerInch), | |
| 1002 current_print_settings_.dpi)); | |
| 1003 size_in_pixels.set_height( | |
| 1004 printing::ConvertUnit(current_print_settings_.printable_area.size.height, | |
| 1005 static_cast<int>(printing::kPointsPerInch), | |
| 1006 current_print_settings_.dpi)); | |
| 1007 // We need to render using the actual printer DPI (rendering to a smaller | |
| 1008 // set of pixels leads to a blurry output). However, we need to counter the | |
| 1009 // scaling up that will happen in the browser. | |
| 1010 XFORM xform = {0}; | |
| 1011 xform.eM11 = xform.eM22 = static_cast<float>(printing::kPointsPerInch) / | |
| 1012 static_cast<float>(current_print_settings_.dpi); | |
| 1013 ModifyWorldTransform(dc, &xform, MWT_LEFTMULTIPLY); | |
| 1014 | |
| 1015 ret = render_proc(buffer->mapped_buffer(), buffer->size(), 0, dc, | |
| 1016 current_print_settings_.dpi, current_print_settings_.dpi, | |
| 1017 0, 0, size_in_pixels.width(), | |
| 1018 size_in_pixels.height(), true, false, true, true); | |
| 1019 #endif // defined(OS_WIN) | |
| 1020 | |
| 1021 return ret; | |
| 1022 } | |
| 1023 | |
| 1024 bool PluginInstance::PrintRasterOutput(PP_Resource print_output, | |
| 1025 WebKit::WebCanvas* canvas) { | |
| 1026 scoped_refptr<ImageData> image(Resource::GetAs<ImageData>(print_output)); | |
| 1027 if (!image.get() || !image->is_mapped()) | |
| 1028 return false; | |
| 1029 | |
| 1030 const SkBitmap* bitmap = image->GetMappedBitmap(); | |
| 1031 if (!bitmap) | |
| 1032 return false; | |
| 1033 | |
| 1034 // Draw the printed image into the supplied canvas. | |
| 1035 SkIRect src_rect; | |
| 1036 src_rect.set(0, 0, bitmap->width(), bitmap->height()); | |
| 1037 SkRect dest_rect; | |
| 1038 dest_rect.set( | |
| 1039 SkIntToScalar(current_print_settings_.printable_area.point.x), | |
| 1040 SkIntToScalar(current_print_settings_.printable_area.point.y), | |
| 1041 SkIntToScalar(current_print_settings_.printable_area.point.x + | |
| 1042 current_print_settings_.printable_area.size.width), | |
| 1043 SkIntToScalar(current_print_settings_.printable_area.point.y + | |
| 1044 current_print_settings_.printable_area.size.height)); | |
| 1045 bool draw_to_canvas = true; | |
| 1046 gfx::Rect dest_rect_gfx; | |
| 1047 dest_rect_gfx.set_x(current_print_settings_.printable_area.point.x); | |
| 1048 dest_rect_gfx.set_y(current_print_settings_.printable_area.point.y); | |
| 1049 dest_rect_gfx.set_width(current_print_settings_.printable_area.size.width); | |
| 1050 dest_rect_gfx.set_height(current_print_settings_.printable_area.size.height); | |
| 1051 | |
| 1052 #if defined(OS_WIN) | |
| 1053 // Since this is a raster output, the size of the bitmap can be | |
| 1054 // huge (especially at high printer DPIs). On Windows, this can | |
| 1055 // result in a HUGE EMF (on Mac and Linux the output goes to PDF | |
| 1056 // which appears to Flate compress the bitmap). So, if this bitmap | |
| 1057 // is larger than 20 MB, we save the bitmap as a JPEG into the EMF | |
| 1058 // DC. Note: We chose JPEG over PNG because JPEG compression seems | |
| 1059 // way faster (about 4 times faster). | |
| 1060 static const int kCompressionThreshold = 20 * 1024 * 1024; | |
| 1061 if (bitmap->getSize() > kCompressionThreshold) { | |
| 1062 DrawJPEGToPlatformDC(*bitmap, dest_rect_gfx, canvas); | |
| 1063 draw_to_canvas = false; | |
| 1064 } | |
| 1065 #endif // defined(OS_WIN) | |
| 1066 #if defined(OS_MACOSX) | |
| 1067 draw_to_canvas = false; | |
| 1068 DrawSkBitmapToCanvas(*bitmap, canvas, dest_rect_gfx, | |
| 1069 current_print_settings_.printable_area.size.height); | |
| 1070 // See comments in the header file. | |
| 1071 last_printed_page_ = image; | |
| 1072 #else // defined(OS_MACOSX) | |
| 1073 if (draw_to_canvas) | |
| 1074 canvas->drawBitmapRect(*bitmap, &src_rect, dest_rect); | |
| 1075 #endif // defined(OS_MACOSX) | |
| 1076 return true; | |
| 1077 } | |
| 1078 | |
| 1079 #if defined(OS_WIN) | |
| 1080 bool PluginInstance::DrawJPEGToPlatformDC( | |
| 1081 const SkBitmap& bitmap, | |
| 1082 const gfx::Rect& printable_area, | |
| 1083 WebKit::WebCanvas* canvas) { | |
| 1084 skia::VectorPlatformDevice& device = | |
| 1085 static_cast<skia::VectorPlatformDevice&>( | |
| 1086 canvas->getTopPlatformDevice()); | |
| 1087 HDC dc = device.getBitmapDC(); | |
| 1088 // TODO(sanjeevr): This is a temporary hack. If we output a JPEG | |
| 1089 // to the EMF, the EnumEnhMetaFile call fails in the browser | |
| 1090 // process. The failure also happens if we output nothing here. | |
| 1091 // We need to investigate the reason for this failure and fix it. | |
| 1092 // In the meantime this temporary hack of drawing an empty | |
| 1093 // rectangle in the DC gets us by. | |
| 1094 Rectangle(dc, 0, 0, 0, 0); | |
| 1095 | |
| 1096 // Ideally we should add JPEG compression to the VectorPlatformDevice class | |
| 1097 // However, Skia currently has no JPEG compression code and we cannot | |
| 1098 // depend on gfx/jpeg_codec.h in Skia. So we do the compression here. | |
| 1099 SkAutoLockPixels lock(bitmap); | |
| 1100 DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config); | |
| 1101 const uint32_t* pixels = | |
| 1102 static_cast<const uint32_t*>(bitmap.getPixels()); | |
| 1103 std::vector<unsigned char> compressed_image; | |
| 1104 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 1105 bool encoded = gfx::JPEGCodec::Encode( | |
| 1106 reinterpret_cast<const unsigned char*>(pixels), | |
| 1107 gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(), bitmap.height(), | |
| 1108 static_cast<int>(bitmap.rowBytes()), 100, &compressed_image); | |
| 1109 UMA_HISTOGRAM_TIMES("PepperPluginPrint.RasterBitmapCompressTime", | |
| 1110 base::TimeTicks::Now() - start_time); | |
| 1111 if (!encoded) { | |
| 1112 NOTREACHED(); | |
| 1113 return false; | |
| 1114 } | |
| 1115 BITMAPINFOHEADER bmi = {0}; | |
| 1116 gfx::CreateBitmapHeader(bitmap.width(), bitmap.height(), &bmi); | |
| 1117 bmi.biCompression = BI_JPEG; | |
| 1118 bmi.biSizeImage = compressed_image.size(); | |
| 1119 bmi.biHeight = -bmi.biHeight; | |
| 1120 StretchDIBits(dc, printable_area.x(), printable_area.y(), | |
| 1121 printable_area.width(), printable_area.height(), | |
| 1122 0, 0, bitmap.width(), bitmap.height(), | |
| 1123 &compressed_image.front(), | |
| 1124 reinterpret_cast<const BITMAPINFO*>(&bmi), | |
| 1125 DIB_RGB_COLORS, SRCCOPY); | |
| 1126 return true; | |
| 1127 } | |
| 1128 #endif // OS_WIN | |
| 1129 | |
| 1130 #if defined(OS_MACOSX) | |
| 1131 void PluginInstance::DrawSkBitmapToCanvas( | |
| 1132 const SkBitmap& bitmap, WebKit::WebCanvas* canvas, | |
| 1133 const gfx::Rect& dest_rect, | |
| 1134 int canvas_height) { | |
| 1135 SkAutoLockPixels lock(bitmap); | |
| 1136 DCHECK(bitmap.getConfig() == SkBitmap::kARGB_8888_Config); | |
| 1137 base::mac::ScopedCFTypeRef<CGDataProviderRef> data_provider( | |
| 1138 CGDataProviderCreateWithData( | |
| 1139 NULL, bitmap.getAddr32(0, 0), | |
| 1140 bitmap.rowBytes() * bitmap.height(), NULL)); | |
| 1141 base::mac::ScopedCFTypeRef<CGImageRef> image( | |
| 1142 CGImageCreate( | |
| 1143 bitmap.width(), bitmap.height(), | |
| 1144 8, 32, bitmap.rowBytes(), | |
| 1145 mac_util::GetSystemColorSpace(), | |
| 1146 kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, | |
| 1147 data_provider, NULL, false, kCGRenderingIntentDefault)); | |
| 1148 | |
| 1149 // Flip the transform | |
| 1150 CGContextSaveGState(canvas); | |
| 1151 CGContextTranslateCTM(canvas, 0, canvas_height); | |
| 1152 CGContextScaleCTM(canvas, 1.0, -1.0); | |
| 1153 | |
| 1154 CGRect bounds; | |
| 1155 bounds.origin.x = dest_rect.x(); | |
| 1156 bounds.origin.y = canvas_height - dest_rect.y() - dest_rect.height(); | |
| 1157 bounds.size.width = dest_rect.width(); | |
| 1158 bounds.size.height = dest_rect.height(); | |
| 1159 | |
| 1160 CGContextDrawImage(canvas, bounds, image); | |
| 1161 CGContextRestoreGState(canvas); | |
| 1162 } | |
| 1163 #endif // defined(OS_MACOSX) | |
| 1164 | |
| 1165 Graphics2D* PluginInstance::bound_graphics_2d() const { | |
| 1166 if (bound_graphics_.get() == NULL) | |
| 1167 return NULL; | |
| 1168 | |
| 1169 return bound_graphics_->Cast<Graphics2D>(); | |
| 1170 } | |
| 1171 | |
| 1172 Graphics3D* PluginInstance::bound_graphics_3d() const { | |
| 1173 if (bound_graphics_.get() == NULL) | |
| 1174 return NULL; | |
| 1175 | |
| 1176 return bound_graphics_->Cast<Graphics3D>(); | |
| 1177 } | |
| 1178 | |
| 1179 } // namespace pepper | |
| OLD | NEW |