1 // Copyright (c) 2011 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 "webkit/plugins/ppapi/ppapi_plugin_instance.h"
7 #include "base/logging.h"
8 #include "base/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "base/scoped_ptr.h"
11 #include "base/utf_string_conversions.h"
12 #include "ppapi/c/dev/ppb_find_dev.h"
13 #include "ppapi/c/dev/ppb_fullscreen_dev.h"
14 #include "ppapi/c/dev/ppb_messaging_dev.h"
15 #include "ppapi/c/dev/ppb_zoom_dev.h"
16 #include "ppapi/c/dev/ppp_find_dev.h"
17 #include "ppapi/c/dev/ppp_messaging_dev.h"
18 #include "ppapi/c/dev/ppp_selection_dev.h"
19 #include "ppapi/c/dev/ppp_zoom_dev.h"
20 #include "ppapi/c/pp_input_event.h"
21 #include "ppapi/c/pp_instance.h"
22 #include "ppapi/c/pp_rect.h"
23 #include "ppapi/c/pp_resource.h"
24 #include "ppapi/c/pp_var.h"
25 #include "ppapi/c/ppb_core.h"
26 #include "ppapi/c/ppb_instance.h"
27 #include "ppapi/c/ppp_instance.h"
28 #include "printing/units.h"
29 #include "skia/ext/vector_platform_device.h"
30 #include "skia/ext/platform_canvas.h"
31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h"
32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
36 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
37 #include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
40 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
41 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
42 #include "ui/gfx/rect.h"
43 #include "ui/gfx/skia_util.h"
44 #include "webkit/plugins/ppapi/common.h"
45 #include "webkit/plugins/ppapi/event_conversion.h"
46 #include "webkit/plugins/ppapi/fullscreen_container.h"
47 #include "webkit/plugins/ppapi/message_channel.h"
48 #include "webkit/plugins/ppapi/plugin_delegate.h"
49 #include "webkit/plugins/ppapi/plugin_module.h"
50 #include "webkit/plugins/ppapi/plugin_object.h"
51 #include "webkit/plugins/ppapi/ppb_buffer_impl.h"
52 #include "webkit/plugins/ppapi/ppb_graphics_2d_impl.h"
53 #include "webkit/plugins/ppapi/ppb_image_data_impl.h"
54 #include "webkit/plugins/ppapi/ppb_surface_3d_impl.h"
55 #include "webkit/plugins/ppapi/ppb_url_loader_impl.h"
56 #include "webkit/plugins/ppapi/ppp_pdf.h"
57 #include "webkit/plugins/ppapi/string.h"
58 #include "webkit/plugins/ppapi/var.h"
59 #include "webkit/plugins/sad_plugin.h"
62 #include "printing/native_metafile.h"
65 #if defined(OS_MACOSX)
66 #include "base/mac/mac_util.h"
67 #include "base/mac/scoped_cftyperef.h"
68 #include "printing/native_metafile_factory.h"
72 #include "printing/native_metafile_skia_wrapper.h"
76 #include "ui/gfx/codec/jpeg_codec.h"
77 #include "ui/gfx/gdi_util.h"
80 using WebKit::WebBindings
;
81 using WebKit::WebCanvas
;
82 using WebKit::WebCursorInfo
;
83 using WebKit::WebDocument
;
84 using WebKit::WebFrame
;
85 using WebKit::WebInputEvent
;
86 using WebKit::WebPluginContainer
;
87 using WebKit::WebString
;
88 using WebKit::WebURLRequest
;
89 using WebKit::WebView
;
95 // Exported by pdf.dll
96 typedef bool (*RenderPDFPageToDCProc
)(
97 const unsigned char* pdf_buffer
, int buffer_size
, int page_number
, HDC dc
,
98 int dpi_x
, int dpi_y
, int bounds_origin_x
, int bounds_origin_y
,
99 int bounds_width
, int bounds_height
, bool fit_to_bounds
,
100 bool stretch_to_bounds
, bool keep_aspect_ratio
, bool center_in_bounds
);
101 #endif // defined(OS_WIN)
105 #define COMPILE_ASSERT_MATCHING_ENUM(webkit_name, np_name) \
106 COMPILE_ASSERT(static_cast<int>(WebCursorInfo::webkit_name) \
107 == static_cast<int>(np_name), \
110 COMPILE_ASSERT_MATCHING_ENUM(TypePointer
, PP_CURSORTYPE_POINTER
);
111 COMPILE_ASSERT_MATCHING_ENUM(TypeCross
, PP_CURSORTYPE_CROSS
);
112 COMPILE_ASSERT_MATCHING_ENUM(TypeHand
, PP_CURSORTYPE_HAND
);
113 COMPILE_ASSERT_MATCHING_ENUM(TypeIBeam
, PP_CURSORTYPE_IBEAM
);
114 COMPILE_ASSERT_MATCHING_ENUM(TypeWait
, PP_CURSORTYPE_WAIT
);
115 COMPILE_ASSERT_MATCHING_ENUM(TypeHelp
, PP_CURSORTYPE_HELP
);
116 COMPILE_ASSERT_MATCHING_ENUM(TypeEastResize
, PP_CURSORTYPE_EASTRESIZE
);
117 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthResize
, PP_CURSORTYPE_NORTHRESIZE
);
118 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastResize
,
119 PP_CURSORTYPE_NORTHEASTRESIZE
);
120 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestResize
,
121 PP_CURSORTYPE_NORTHWESTRESIZE
);
122 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthResize
, PP_CURSORTYPE_SOUTHRESIZE
);
123 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastResize
,
124 PP_CURSORTYPE_SOUTHEASTRESIZE
);
125 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestResize
,
126 PP_CURSORTYPE_SOUTHWESTRESIZE
);
127 COMPILE_ASSERT_MATCHING_ENUM(TypeWestResize
, PP_CURSORTYPE_WESTRESIZE
);
128 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthSouthResize
,
129 PP_CURSORTYPE_NORTHSOUTHRESIZE
);
130 COMPILE_ASSERT_MATCHING_ENUM(TypeEastWestResize
, PP_CURSORTYPE_EASTWESTRESIZE
);
131 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastSouthWestResize
,
132 PP_CURSORTYPE_NORTHEASTSOUTHWESTRESIZE
);
133 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestSouthEastResize
,
134 PP_CURSORTYPE_NORTHWESTSOUTHEASTRESIZE
);
135 COMPILE_ASSERT_MATCHING_ENUM(TypeColumnResize
, PP_CURSORTYPE_COLUMNRESIZE
);
136 COMPILE_ASSERT_MATCHING_ENUM(TypeRowResize
, PP_CURSORTYPE_ROWRESIZE
);
137 COMPILE_ASSERT_MATCHING_ENUM(TypeMiddlePanning
, PP_CURSORTYPE_MIDDLEPANNING
);
138 COMPILE_ASSERT_MATCHING_ENUM(TypeEastPanning
, PP_CURSORTYPE_EASTPANNING
);
139 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthPanning
, PP_CURSORTYPE_NORTHPANNING
);
140 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthEastPanning
,
141 PP_CURSORTYPE_NORTHEASTPANNING
);
142 COMPILE_ASSERT_MATCHING_ENUM(TypeNorthWestPanning
,
143 PP_CURSORTYPE_NORTHWESTPANNING
);
144 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthPanning
, PP_CURSORTYPE_SOUTHPANNING
);
145 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthEastPanning
,
146 PP_CURSORTYPE_SOUTHEASTPANNING
);
147 COMPILE_ASSERT_MATCHING_ENUM(TypeSouthWestPanning
,
148 PP_CURSORTYPE_SOUTHWESTPANNING
);
149 COMPILE_ASSERT_MATCHING_ENUM(TypeWestPanning
, PP_CURSORTYPE_WESTPANNING
);
150 COMPILE_ASSERT_MATCHING_ENUM(TypeMove
, PP_CURSORTYPE_MOVE
);
151 COMPILE_ASSERT_MATCHING_ENUM(TypeVerticalText
, PP_CURSORTYPE_VERTICALTEXT
);
152 COMPILE_ASSERT_MATCHING_ENUM(TypeCell
, PP_CURSORTYPE_CELL
);
153 COMPILE_ASSERT_MATCHING_ENUM(TypeContextMenu
, PP_CURSORTYPE_CONTEXTMENU
);
154 COMPILE_ASSERT_MATCHING_ENUM(TypeAlias
, PP_CURSORTYPE_ALIAS
);
155 COMPILE_ASSERT_MATCHING_ENUM(TypeProgress
, PP_CURSORTYPE_PROGRESS
);
156 COMPILE_ASSERT_MATCHING_ENUM(TypeNoDrop
, PP_CURSORTYPE_NODROP
);
157 COMPILE_ASSERT_MATCHING_ENUM(TypeCopy
, PP_CURSORTYPE_COPY
);
158 COMPILE_ASSERT_MATCHING_ENUM(TypeNone
, PP_CURSORTYPE_NONE
);
159 COMPILE_ASSERT_MATCHING_ENUM(TypeNotAllowed
, PP_CURSORTYPE_NOTALLOWED
);
160 COMPILE_ASSERT_MATCHING_ENUM(TypeZoomIn
, PP_CURSORTYPE_ZOOMIN
);
161 COMPILE_ASSERT_MATCHING_ENUM(TypeZoomOut
, PP_CURSORTYPE_ZOOMOUT
);
162 COMPILE_ASSERT_MATCHING_ENUM(TypeGrab
, PP_CURSORTYPE_GRAB
);
163 COMPILE_ASSERT_MATCHING_ENUM(TypeGrabbing
, PP_CURSORTYPE_GRABBING
);
164 // Do not assert WebCursorInfo::TypeCustom == PP_CURSORTYPE_CUSTOM;
165 // PP_CURSORTYPE_CUSTOM is pinned to allow new cursor types.
167 void RectToPPRect(const gfx::Rect
& input
, PP_Rect
* output
) {
168 *output
= PP_MakeRectFromXYWH(input
.x(), input
.y(),
169 input
.width(), input
.height());
172 PP_Var
GetWindowObject(PP_Instance instance_id
) {
173 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
175 return PP_MakeUndefined();
176 return instance
->GetWindowObject();
179 PP_Var
GetOwnerElementObject(PP_Instance instance_id
) {
180 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
182 return PP_MakeUndefined();
183 return instance
->GetOwnerElementObject();
186 PP_Bool
BindGraphics(PP_Instance instance_id
, PP_Resource graphics_id
) {
187 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
190 return BoolToPPBool(instance
->BindGraphics(graphics_id
));
193 PP_Bool
IsFullFrame(PP_Instance instance_id
) {
194 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
197 return BoolToPPBool(instance
->full_frame());
200 PP_Var
ExecuteScript(PP_Instance instance_id
,
203 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
205 return PP_MakeUndefined();
206 return instance
->ExecuteScript(script
, exception
);
209 const PPB_Instance ppb_instance
= {
211 &GetOwnerElementObject
,
217 void NumberOfFindResultsChanged(PP_Instance instance_id
,
219 PP_Bool final_result
) {
220 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
224 DCHECK_NE(instance
->find_identifier(), -1);
225 instance
->delegate()->NumberOfFindResultsChanged(
226 instance
->find_identifier(), total
, PPBoolToBool(final_result
));
229 void SelectedFindResultChanged(PP_Instance instance_id
,
231 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
235 DCHECK_NE(instance
->find_identifier(), -1);
236 instance
->delegate()->SelectedFindResultChanged(
237 instance
->find_identifier(), index
);
240 const PPB_Find_Dev ppb_find
= {
241 &NumberOfFindResultsChanged
,
242 &SelectedFindResultChanged
,
245 PP_Bool
IsFullscreen(PP_Instance instance_id
) {
246 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
249 return BoolToPPBool(instance
->IsFullscreen());
252 PP_Bool
SetFullscreen(PP_Instance instance_id
, PP_Bool fullscreen
) {
253 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
256 instance
->SetFullscreen(PPBoolToBool(fullscreen
), true);
260 PP_Bool
GetScreenSize(PP_Instance instance_id
, PP_Size
* size
) {
261 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
262 if (!instance
|| !size
)
264 gfx::Size screen_size
= instance
->delegate()->GetScreenSize();
265 *size
= PP_MakeSize(screen_size
.width(), screen_size
.height());
269 const PPB_Fullscreen_Dev ppb_fullscreen
= {
275 void PostMessage(PP_Instance instance_id
, PP_Var message
) {
276 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
279 instance
->PostMessage(message
);
282 const PPB_Messaging_Dev ppb_messaging
= {
286 void ZoomChanged(PP_Instance instance_id
, double factor
) {
287 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
291 // We only want to tell the page to change its zoom if the whole page is the
292 // plugin. If we're in an iframe, then don't do anything.
293 if (!instance
->IsFullPagePlugin())
296 double zoom_level
= WebView::zoomFactorToZoomLevel(factor
);
297 // The conversino from zoom level to factor, and back, can introduce rounding
298 // errors. i.e. WebKit originally tells us 3.0, but by the time we tell the
299 // plugin and it tells us back, the level becomes 3.000000000004. Need to
300 // round or else otherwise if the user zooms out, it will go to 3.0 instead of
303 static_cast<int>(zoom_level
+ (zoom_level
> 0 ? 0.001 : -0.001));
304 if (abs(rounded
- zoom_level
) < 0.001)
305 zoom_level
= rounded
;
306 instance
->container()->zoomLevelChanged(zoom_level
);
309 void ZoomLimitsChanged(PP_Instance instance_id
,
310 double minimum_factor
,
311 double maximium_factor
) {
312 if (minimum_factor
> maximium_factor
) {
317 PluginInstance
* instance
= ResourceTracker::Get()->GetInstance(instance_id
);
320 instance
->delegate()->ZoomLimitsChanged(minimum_factor
, maximium_factor
);
323 const PPB_Zoom_Dev ppb_zoom
= {
330 PluginInstance::PluginInstance(PluginDelegate
* delegate
,
331 PluginModule
* module
,
332 const PPP_Instance
* instance_interface
)
333 : delegate_(delegate
),
335 instance_interface_(instance_interface
),
339 has_webkit_focus_(false),
340 has_content_area_focus_(false),
341 find_identifier_(-1),
342 plugin_find_interface_(NULL
),
343 plugin_messaging_interface_(NULL
),
344 plugin_pdf_interface_(NULL
),
345 plugin_selection_interface_(NULL
),
346 plugin_zoom_interface_(NULL
),
347 checked_for_plugin_messaging_interface_(false),
348 #if defined(OS_LINUX)
350 #endif // defined(OS_LINUX)
351 plugin_print_interface_(NULL
),
352 plugin_graphics_3d_interface_(NULL
),
353 always_on_top_(false),
354 fullscreen_container_(NULL
),
356 message_channel_(NULL
),
358 pp_instance_
= ResourceTracker::Get()->AddInstance(this);
360 memset(¤t_print_settings_
, 0, sizeof(current_print_settings_
));
362 module_
->InstanceCreated(this);
363 delegate_
->InstanceCreated(this);
364 message_channel_
.reset(new MessageChannel(this));
367 PluginInstance::~PluginInstance() {
368 // Free all the plugin objects. This will automatically clear the back-
369 // pointer from the NPObject so WebKit can't call into the plugin any more.
371 // Swap out the set so we can delete from it (the objects will try to
372 // unregister themselves inside the delete call).
373 PluginObjectSet plugin_object_copy
;
374 live_plugin_objects_
.swap(plugin_object_copy
);
375 for (PluginObjectSet::iterator i
= plugin_object_copy
.begin();
376 i
!= plugin_object_copy
.end(); ++i
)
379 delegate_
->InstanceDeleted(this);
380 module_
->InstanceDeleted(this);
382 ResourceTracker::Get()->InstanceDeleted(pp_instance_
);
383 #if defined(OS_LINUX)
385 #endif // defined(OS_LINUX)
389 const PPB_Instance
* PluginInstance::GetInterface() {
390 return &ppb_instance
;
394 const PPB_Find_Dev
* PluginInstance::GetFindInterface() {
399 const PPB_Fullscreen_Dev
* PluginInstance::GetFullscreenInterface() {
400 return &ppb_fullscreen
;
404 const PPB_Messaging_Dev
* PluginInstance::GetMessagingInterface() {
405 return &ppb_messaging
;
409 const PPB_Zoom_Dev
* PluginInstance::GetZoomInterface() {
413 // NOTE: Any of these methods that calls into the plugin needs to take into
414 // account that the plugin may use Var to remove the <embed> from the DOM, which
415 // will make the WebPluginImpl drop its reference, usually the last one. If a
416 // method needs to access a member of the instance after the call has returned,
417 // then it needs to keep its own reference on the stack.
419 void PluginInstance::Paint(WebCanvas
* canvas
,
420 const gfx::Rect
& plugin_rect
,
421 const gfx::Rect
& paint_rect
) {
422 if (module()->is_crashed()) {
423 // Crashed plugin painting.
424 if (!sad_plugin_
) // Lazily initialize bitmap.
425 sad_plugin_
= delegate_
->GetSadPluginBitmap();
427 webkit::PaintSadPlugin(canvas
, plugin_rect
, *sad_plugin_
);
431 if (bound_graphics_2d())
432 bound_graphics_2d()->Paint(canvas
, plugin_rect
, paint_rect
);
435 void PluginInstance::InvalidateRect(const gfx::Rect
& rect
) {
436 if (fullscreen_container_
) {
438 fullscreen_container_
->Invalidate();
440 fullscreen_container_
->InvalidateRect(rect
);
442 if (!container_
|| position_
.IsEmpty())
443 return; // Nothing to do.
445 container_
->invalidate();
447 container_
->invalidateRect(rect
);
451 void PluginInstance::ScrollRect(int dx
, int dy
, const gfx::Rect
& rect
) {
452 if (fullscreen_container_
) {
453 fullscreen_container_
->ScrollRect(dx
, dy
, rect
);
456 container_
->scrollRect(dx
, dy
, rect
);
458 // Can't do optimized scrolling since there could be other elements on top
460 InvalidateRect(rect
);
465 unsigned PluginInstance::GetBackingTextureId() {
466 if (!bound_graphics_3d())
469 return bound_graphics_3d()->GetBackingTextureId();
472 void PluginInstance::CommitBackingTexture() {
473 if (fullscreen_container_
)
474 fullscreen_container_
->Invalidate();
476 container_
->commitBackingTexture();
479 void PluginInstance::InstanceCrashed() {
480 // Force free all resources and vars.
481 ResourceTracker::Get()->InstanceCrashed(pp_instance());
483 // Free any associated graphics.
484 SetFullscreen(false, false);
485 bound_graphics_
= NULL
;
486 InvalidateRect(gfx::Rect());
488 delegate()->PluginCrashed(this);
491 PP_Var
PluginInstance::GetWindowObject() {
493 return PP_MakeUndefined();
495 WebFrame
* frame
= container_
->element().document().frame();
497 return PP_MakeUndefined();
499 return ObjectVar::NPObjectToPPVar(this, frame
->windowObject());
502 PP_Var
PluginInstance::GetOwnerElementObject() {
504 return PP_MakeUndefined();
505 return ObjectVar::NPObjectToPPVar(this,
506 container_
->scriptableObjectForElement());
509 bool PluginInstance::BindGraphics(PP_Resource graphics_id
) {
511 // Special-case clearing the current device.
512 if (bound_graphics_
.get()) {
513 if (bound_graphics_2d()) {
514 bound_graphics_2d()->BindToInstance(NULL
);
515 } else if (bound_graphics_
.get()) {
516 bound_graphics_3d()->BindToInstance(false);
518 setBackingTextureId(0);
519 InvalidateRect(gfx::Rect());
521 bound_graphics_
= NULL
;
525 scoped_refptr
<PPB_Graphics2D_Impl
> graphics_2d
=
526 Resource::GetAs
<PPB_Graphics2D_Impl
>(graphics_id
);
527 scoped_refptr
<PPB_Surface3D_Impl
> graphics_3d
=
528 Resource::GetAs
<PPB_Surface3D_Impl
>(graphics_id
);
531 // Refuse to bind if we're transitioning to fullscreen.
532 if (fullscreen_container_
&& !fullscreen_
)
534 if (!graphics_2d
->BindToInstance(this))
535 return false; // Can't bind to more than one instance.
537 // See http://crbug.com/49403: this can be further optimized by keeping the
538 // old device around and painting from it.
539 if (bound_graphics_2d()) {
540 // Start the new image with the content of the old image until the plugin
542 // Use ImageDataAutoMapper to ensure the image data is valid.
543 ImageDataAutoMapper
mapper(bound_graphics_2d()->image_data());
544 if (!mapper
.is_valid())
546 const SkBitmap
* old_backing_bitmap
=
547 bound_graphics_2d()->image_data()->GetMappedBitmap();
548 SkRect old_size
= SkRect::MakeWH(
549 SkScalar(static_cast<float>(old_backing_bitmap
->width())),
550 SkScalar(static_cast<float>(old_backing_bitmap
->height())));
552 SkCanvas
canvas(*graphics_2d
->image_data()->GetMappedBitmap());
553 canvas
.drawBitmap(*old_backing_bitmap
, 0, 0);
555 // Fill in any extra space with white.
556 canvas
.clipRect(old_size
, SkRegion::kDifference_Op
);
557 canvas
.drawARGB(255, 255, 255, 255);
560 bound_graphics_
= graphics_2d
;
561 setBackingTextureId(0);
562 // BindToInstance will have invalidated the plugin if necessary.
563 } else if (graphics_3d
) {
564 // Refuse to bind if we're transitioning to fullscreen.
565 if (fullscreen_container_
&& !fullscreen_
)
567 // Make sure graphics can only be bound to the instance it is
569 if (graphics_3d
->instance() != this)
571 if (!graphics_3d
->BindToInstance(true))
574 setBackingTextureId(graphics_3d
->GetBackingTextureId());
575 bound_graphics_
= graphics_3d
;
581 bool PluginInstance::SetCursor(PP_CursorType_Dev type
,
582 PP_Resource custom_image
,
583 const PP_Point
* hot_spot
) {
584 if (type
!= PP_CURSORTYPE_CUSTOM
) {
585 cursor_
.reset(new WebCursorInfo(static_cast<WebCursorInfo::Type
>(type
)));
592 scoped_refptr
<PPB_ImageData_Impl
> image_data(
593 Resource::GetAs
<PPB_ImageData_Impl
>(custom_image
));
594 if (!image_data
.get())
597 if (image_data
->format() != PPB_ImageData_Impl::GetNativeImageDataFormat()) {
598 // TODO(yzshen): Handle the case that the image format is different from the
604 ImageDataAutoMapper
auto_mapper(image_data
);
605 if (!auto_mapper
.is_valid())
608 scoped_ptr
<WebCursorInfo
> custom_cursor(
609 new WebCursorInfo(WebCursorInfo::TypeCustom
));
610 custom_cursor
->hotSpot
.x
= hot_spot
->x
;
611 custom_cursor
->hotSpot
.y
= hot_spot
->y
;
613 #if WEBKIT_USING_SKIA
614 const SkBitmap
* bitmap
= image_data
->GetMappedBitmap();
615 // Make a deep copy, so that the cursor remains valid even after the original
616 // image data gets freed.
617 if (!bitmap
->copyTo(&custom_cursor
->customImage
.getSkBitmap(),
621 #elif WEBKIT_USING_CG
622 // TODO(yzshen): Implement it.
627 cursor_
.reset(custom_cursor
.release());
631 PP_Var
PluginInstance::ExecuteScript(PP_Var script
, PP_Var
* exception
) {
632 TryCatch
try_catch(module(), exception
);
633 if (try_catch
.has_exception())
634 return PP_MakeUndefined();
636 // Convert the script into an inconvenient NPString object.
637 scoped_refptr
<StringVar
> script_string(StringVar::FromPPVar(script
));
638 if (!script_string
) {
639 try_catch
.SetException("Script param to ExecuteScript must be a string.");
640 return PP_MakeUndefined();
643 np_script
.UTF8Characters
= script_string
->value().c_str();
644 np_script
.UTF8Length
= script_string
->value().length();
646 // Get the current frame to pass to the evaluate function.
647 WebFrame
* frame
= container_
->element().document().frame();
649 try_catch
.SetException("No frame to execute script in.");
650 return PP_MakeUndefined();
654 bool ok
= WebBindings::evaluate(NULL
, frame
->windowObject(), &np_script
,
657 // TODO(brettw) bug 54011: The TryCatch isn't working properly and
658 // doesn't actually catch this exception.
659 try_catch
.SetException("Exception caught");
660 WebBindings::releaseVariantValue(&result
);
661 return PP_MakeUndefined();
664 PP_Var ret
= Var::NPVariantToPPVar(this, &result
);
665 WebBindings::releaseVariantValue(&result
);
669 void PluginInstance::PostMessage(PP_Var message
) {
670 message_channel_
->PostMessageToJavaScript(message
);
673 void PluginInstance::Delete() {
674 // Keep a reference on the stack. See NOTE above.
675 scoped_refptr
<PluginInstance
> ref(this);
676 instance_interface_
->DidDestroy(pp_instance());
678 if (fullscreen_container_
) {
679 fullscreen_container_
->Destroy();
680 fullscreen_container_
= NULL
;
685 bool PluginInstance::Initialize(WebPluginContainer
* container
,
686 const std::vector
<std::string
>& arg_names
,
687 const std::vector
<std::string
>& arg_values
,
689 container_
= container
;
690 full_frame_
= full_frame
;
693 scoped_array
<const char*> argn(new const char*[arg_names
.size()]);
694 scoped_array
<const char*> argv(new const char*[arg_names
.size()]);
695 for (size_t i
= 0; i
< arg_names
.size(); ++i
) {
696 argn
[argc
] = arg_names
[i
].c_str();
697 argv
[argc
] = arg_values
[i
].c_str();
701 return PPBoolToBool(instance_interface_
->DidCreate(pp_instance(),
707 bool PluginInstance::HandleDocumentLoad(PPB_URLLoader_Impl
* loader
) {
708 Resource::ScopedResourceId
resource(loader
);
709 return PPBoolToBool(instance_interface_
->HandleDocumentLoad(pp_instance(),
713 bool PluginInstance::HandleInputEvent(const WebKit::WebInputEvent
& event
,
714 WebCursorInfo
* cursor_info
) {
715 // Keep a reference on the stack. See NOTE above.
716 scoped_refptr
<PluginInstance
> ref(this);
717 std::vector
<PP_InputEvent
> pp_events
;
718 CreatePPEvent(event
, &pp_events
);
720 // Each input event may generate more than one PP_InputEvent.
722 for (size_t i
= 0; i
< pp_events
.size(); i
++) {
723 rv
|= PPBoolToBool(instance_interface_
->HandleInputEvent(pp_instance(),
728 *cursor_info
= *cursor_
;
732 void PluginInstance::HandleMessage(PP_Var message
) {
733 // Keep a reference on the stack. See NOTE above.
734 scoped_refptr
<PluginInstance
> ref(this);
735 if (!LoadMessagingInterface())
737 plugin_messaging_interface_
->HandleMessage(pp_instance(), message
);
740 PP_Var
PluginInstance::GetInstanceObject() {
741 return instance_interface_
->GetInstanceObject(pp_instance());
744 void PluginInstance::ViewChanged(const gfx::Rect
& position
,
745 const gfx::Rect
& clip
) {
746 fullscreen_
= (fullscreen_container_
!= NULL
);
747 position_
= position
;
749 if (clip
.IsEmpty()) {
750 // WebKit can give weird (x,y) positions for empty clip rects (since the
751 // position technically doesn't matter). But we want to make these
752 // consistent since this is given to the plugin, so force everything to 0
753 // in the "everything is clipped" case.
759 PP_Rect pp_position
, pp_clip
;
760 RectToPPRect(position_
, &pp_position
);
761 RectToPPRect(clip_
, &pp_clip
);
762 instance_interface_
->DidChangeView(pp_instance(), &pp_position
, &pp_clip
);
765 void PluginInstance::SetWebKitFocus(bool has_focus
) {
766 if (has_webkit_focus_
== has_focus
)
769 bool old_plugin_focus
= PluginHasFocus();
770 has_webkit_focus_
= has_focus
;
771 if (PluginHasFocus() != old_plugin_focus
) {
772 instance_interface_
->DidChangeFocus(pp_instance(),
773 BoolToPPBool(PluginHasFocus()));
777 void PluginInstance::SetContentAreaFocus(bool has_focus
) {
778 if (has_content_area_focus_
== has_focus
)
781 bool old_plugin_focus
= PluginHasFocus();
782 has_content_area_focus_
= has_focus
;
783 if (PluginHasFocus() != old_plugin_focus
) {
784 instance_interface_
->DidChangeFocus(pp_instance(),
785 BoolToPPBool(PluginHasFocus()));
789 void PluginInstance::ViewInitiatedPaint() {
790 if (bound_graphics_2d())
791 bound_graphics_2d()->ViewInitiatedPaint();
792 if (bound_graphics_3d())
793 bound_graphics_3d()->ViewInitiatedPaint();
796 void PluginInstance::ViewFlushedPaint() {
797 // Keep a reference on the stack. See NOTE above.
798 scoped_refptr
<PluginInstance
> ref(this);
799 if (bound_graphics_2d())
800 bound_graphics_2d()->ViewFlushedPaint();
801 if (bound_graphics_3d())
802 bound_graphics_3d()->ViewFlushedPaint();
805 bool PluginInstance::GetBitmapForOptimizedPluginPaint(
806 const gfx::Rect
& paint_bounds
,
812 if (!bound_graphics_2d() || !bound_graphics_2d()->is_always_opaque())
815 // We specifically want to compare against the area covered by the backing
816 // store when seeing if we cover the given paint bounds, since the backing
817 // store could be smaller than the declared plugin area.
818 PPB_ImageData_Impl
* image_data
= bound_graphics_2d()->image_data();
819 gfx::Rect
plugin_backing_store_rect(position_
.origin(),
820 gfx::Size(image_data
->width(),
821 image_data
->height()));
822 gfx::Rect
clip_page(clip_
);
823 clip_page
.Offset(position_
.origin());
824 gfx::Rect plugin_paint_rect
= plugin_backing_store_rect
.Intersect(clip_page
);
825 if (!plugin_paint_rect
.Contains(paint_bounds
))
828 *dib
= image_data
->platform_image()->GetTransportDIB();
829 *location
= plugin_backing_store_rect
;
834 string16
PluginInstance::GetSelectedText(bool html
) {
835 // Keep a reference on the stack. See NOTE above.
836 scoped_refptr
<PluginInstance
> ref(this);
837 if (!LoadSelectionInterface())
840 PP_Var rv
= plugin_selection_interface_
->GetSelectedText(pp_instance(),
842 scoped_refptr
<StringVar
> string(StringVar::FromPPVar(rv
));
843 Var::PluginReleasePPVar(rv
); // Release the ref the plugin transfered to us.
846 return UTF8ToUTF16(string
->value());
849 string16
PluginInstance::GetLinkAtPosition(const gfx::Point
& point
) {
850 // Keep a reference on the stack. See NOTE above.
851 scoped_refptr
<PluginInstance
> ref(this);
852 if (!LoadPdfInterface())
858 PP_Var rv
= plugin_pdf_interface_
->GetLinkAtPosition(pp_instance(), p
);
859 scoped_refptr
<StringVar
> string(StringVar::FromPPVar(rv
));
860 Var::PluginReleasePPVar(rv
); // Release the ref the plugin transfered to us.
863 return UTF8ToUTF16(string
->value());
866 void PluginInstance::Zoom(double factor
, bool text_only
) {
867 // Keep a reference on the stack. See NOTE above.
868 scoped_refptr
<PluginInstance
> ref(this);
869 if (!LoadZoomInterface())
871 plugin_zoom_interface_
->Zoom(pp_instance(), factor
, BoolToPPBool(text_only
));
874 bool PluginInstance::StartFind(const string16
& search_text
,
877 // Keep a reference on the stack. See NOTE above.
878 scoped_refptr
<PluginInstance
> ref(this);
879 if (!LoadFindInterface())
881 find_identifier_
= identifier
;
883 plugin_find_interface_
->StartFind(
885 UTF16ToUTF8(search_text
.c_str()).c_str(),
886 BoolToPPBool(case_sensitive
)));
889 void PluginInstance::SelectFindResult(bool forward
) {
890 // Keep a reference on the stack. See NOTE above.
891 scoped_refptr
<PluginInstance
> ref(this);
892 if (LoadFindInterface())
893 plugin_find_interface_
->SelectFindResult(pp_instance(),
894 BoolToPPBool(forward
));
897 void PluginInstance::StopFind() {
898 // Keep a reference on the stack. See NOTE above.
899 scoped_refptr
<PluginInstance
> ref(this);
900 if (!LoadFindInterface())
902 find_identifier_
= -1;
903 plugin_find_interface_
->StopFind(pp_instance());
906 bool PluginInstance::LoadFindInterface() {
907 if (!plugin_find_interface_
) {
908 plugin_find_interface_
=
909 reinterpret_cast<const PPP_Find_Dev
*>(module_
->GetPluginInterface(
910 PPP_FIND_DEV_INTERFACE
));
913 return !!plugin_find_interface_
;
916 bool PluginInstance::LoadMessagingInterface() {
917 if (!checked_for_plugin_messaging_interface_
) {
918 checked_for_plugin_messaging_interface_
= true;
919 plugin_messaging_interface_
=
920 reinterpret_cast<const PPP_Messaging_Dev
*>(module_
->GetPluginInterface(
921 PPP_MESSAGING_DEV_INTERFACE
));
924 return !!plugin_messaging_interface_
;
927 bool PluginInstance::LoadPdfInterface() {
928 if (!plugin_pdf_interface_
) {
929 plugin_pdf_interface_
=
930 reinterpret_cast<const PPP_Pdf
*>(module_
->GetPluginInterface(
934 return !!plugin_pdf_interface_
;
937 bool PluginInstance::LoadSelectionInterface() {
938 if (!plugin_selection_interface_
) {
939 plugin_selection_interface_
=
940 reinterpret_cast<const PPP_Selection_Dev
*>(module_
->GetPluginInterface(
941 PPP_SELECTION_DEV_INTERFACE
));
944 return !!plugin_selection_interface_
;
947 bool PluginInstance::LoadZoomInterface() {
948 if (!plugin_zoom_interface_
) {
949 plugin_zoom_interface_
=
950 reinterpret_cast<const PPP_Zoom_Dev
*>(module_
->GetPluginInterface(
951 PPP_ZOOM_DEV_INTERFACE
));
954 return !!plugin_zoom_interface_
;
957 bool PluginInstance::PluginHasFocus() const {
958 return has_webkit_focus_
&& has_content_area_focus_
;
961 void PluginInstance::ReportGeometry() {
962 // If this call was delayed, we may have transitioned back to fullscreen in
963 // the mean time, so only report the geometry if we are actually in normal
965 if (container_
&& !fullscreen_container_
)
966 container_
->reportGeometry();
969 bool PluginInstance::GetPreferredPrintOutputFormat(
970 PP_PrintOutputFormat_Dev
* format
) {
971 // Keep a reference on the stack. See NOTE above.
972 scoped_refptr
<PluginInstance
> ref(this);
973 if (!plugin_print_interface_
) {
974 plugin_print_interface_
=
975 reinterpret_cast<const PPP_Printing_Dev
*>(module_
->GetPluginInterface(
976 PPP_PRINTING_DEV_INTERFACE
));
978 if (!plugin_print_interface_
)
980 uint32_t format_count
= 0;
981 PP_PrintOutputFormat_Dev
* supported_formats
=
982 plugin_print_interface_
->QuerySupportedFormats(pp_instance(),
984 if (!supported_formats
)
987 bool found_supported_format
= false;
988 for (uint32_t index
= 0; index
< format_count
; index
++) {
989 if (supported_formats
[index
] == PP_PRINTOUTPUTFORMAT_PDF
) {
990 // If we found PDF, we are done.
991 found_supported_format
= true;
992 *format
= PP_PRINTOUTPUTFORMAT_PDF
;
994 } else if (supported_formats
[index
] == PP_PRINTOUTPUTFORMAT_RASTER
) {
995 // We found raster. Keep looking.
996 found_supported_format
= true;
997 *format
= PP_PRINTOUTPUTFORMAT_RASTER
;
1000 PluginModule::GetCore()->MemFree(supported_formats
);
1001 return found_supported_format
;
1004 bool PluginInstance::SupportsPrintInterface() {
1005 PP_PrintOutputFormat_Dev format
;
1006 return GetPreferredPrintOutputFormat(&format
);
1009 int PluginInstance::PrintBegin(const gfx::Rect
& printable_area
,
1011 // Keep a reference on the stack. See NOTE above.
1012 scoped_refptr
<PluginInstance
> ref(this);
1013 PP_PrintOutputFormat_Dev format
;
1014 if (!GetPreferredPrintOutputFormat(&format
)) {
1015 // PrintBegin should not have been called since SupportsPrintInterface
1016 // would have returned false;
1021 PP_PrintSettings_Dev print_settings
;
1022 RectToPPRect(printable_area
, &print_settings
.printable_area
);
1023 print_settings
.dpi
= printer_dpi
;
1024 print_settings
.orientation
= PP_PRINTORIENTATION_NORMAL
;
1025 print_settings
.grayscale
= PP_FALSE
;
1026 print_settings
.format
= format
;
1027 int num_pages
= plugin_print_interface_
->Begin(pp_instance(),
1031 current_print_settings_
= print_settings
;
1032 #if defined(OS_LINUX)
1035 #endif // defined(OS_LINUX)
1039 bool PluginInstance::PrintPage(int page_number
, WebKit::WebCanvas
* canvas
) {
1040 DCHECK(plugin_print_interface_
);
1041 PP_PrintPageNumberRange_Dev page_range
;
1042 page_range
.first_page_number
= page_range
.last_page_number
= page_number
;
1043 #if defined(OS_LINUX)
1044 ranges_
.push_back(page_range
);
1048 return PrintPageHelper(&page_range
, 1, canvas
);
1049 #endif // defined(OS_LINUX)
1052 bool PluginInstance::PrintPageHelper(PP_PrintPageNumberRange_Dev
* page_ranges
,
1054 WebKit::WebCanvas
* canvas
) {
1055 // Keep a reference on the stack. See NOTE above.
1056 scoped_refptr
<PluginInstance
> ref(this);
1057 PP_Resource print_output
= plugin_print_interface_
->PrintPages(
1058 pp_instance(), page_ranges
, num_ranges
);
1064 if (current_print_settings_
.format
== PP_PRINTOUTPUTFORMAT_PDF
)
1065 ret
= PrintPDFOutput(print_output
, canvas
);
1066 else if (current_print_settings_
.format
== PP_PRINTOUTPUTFORMAT_RASTER
)
1067 ret
= PrintRasterOutput(print_output
, canvas
);
1069 // Now we need to release the print output resource.
1070 PluginModule::GetCore()->ReleaseResource(print_output
);
1075 void PluginInstance::PrintEnd() {
1076 // Keep a reference on the stack. See NOTE above.
1077 scoped_refptr
<PluginInstance
> ref(this);
1078 #if defined(OS_LINUX)
1079 // This hack is here because all pages need to be written to PDF at once.
1080 if (!ranges_
.empty())
1081 PrintPageHelper(&(ranges_
.front()), ranges_
.size(), canvas_
);
1084 #endif // defined(OS_LINUX)
1086 DCHECK(plugin_print_interface_
);
1087 if (plugin_print_interface_
)
1088 plugin_print_interface_
->End(pp_instance());
1090 memset(¤t_print_settings_
, 0, sizeof(current_print_settings_
));
1091 #if defined(OS_MACOSX)
1092 last_printed_page_
= NULL
;
1093 #endif // defined(OS_MACOSX)
1096 bool PluginInstance::IsFullscreen() {
1100 bool PluginInstance::IsFullscreenOrPending() {
1101 return fullscreen_container_
!= NULL
;
1104 void PluginInstance::SetFullscreen(bool fullscreen
, bool delay_report
) {
1105 // Keep a reference on the stack. See NOTE above.
1106 scoped_refptr
<PluginInstance
> ref(this);
1108 // We check whether we are trying to switch to the state we're already going
1109 // to (i.e. if we're already switching to fullscreen but the fullscreen
1110 // container isn't ready yet, don't do anything more).
1111 if (fullscreen
== IsFullscreenOrPending())
1115 VLOG(1) << "Setting fullscreen to " << (fullscreen
? "on" : "off");
1117 DCHECK(!fullscreen_container_
);
1118 fullscreen_container_
= delegate_
->CreateFullscreenContainer(this);
1120 DCHECK(fullscreen_container_
);
1121 fullscreen_container_
->Destroy();
1122 fullscreen_container_
= NULL
;
1123 fullscreen_
= false;
1124 if (!delay_report
) {
1127 MessageLoop::current()->PostTask(
1128 FROM_HERE
, NewRunnableMethod(this, &PluginInstance::ReportGeometry
));
1133 bool PluginInstance::NavigateToURL(const char* url
, const char* target
) {
1134 if (!url
|| !target
|| !container_
)
1137 WebDocument document
= container_
->element().document();
1138 GURL complete_url
= document
.completeURL(WebString::fromUTF8(url
));
1139 // Don't try to deal with the security issues of javascript.
1140 if (complete_url
.SchemeIs("javascript"))
1143 WebURLRequest
request(complete_url
);
1144 document
.frame()->setReferrerForRequest(request
, GURL());
1145 request
.setHTTPMethod(WebString::fromUTF8("GET"));
1146 request
.setFirstPartyForCookies(document
.firstPartyForCookies());
1147 request
.setHasUserGesture(true);
1149 WebString target_str
= WebString::fromUTF8(target
);
1150 container_
->loadFrameRequest(request
, target_str
, false, NULL
);
1154 PluginDelegate::PlatformContext3D
* PluginInstance::CreateContext3D() {
1155 if (fullscreen_container_
)
1156 return fullscreen_container_
->CreateContext3D();
1158 return delegate_
->CreateContext3D();
1161 bool PluginInstance::PrintPDFOutput(PP_Resource print_output
,
1162 WebKit::WebCanvas
* canvas
) {
1163 scoped_refptr
<PPB_Buffer_Impl
> buffer(
1164 Resource::GetAs
<PPB_Buffer_Impl
>(print_output
));
1165 if (!buffer
.get() || !buffer
->is_mapped() || !buffer
->size()) {
1170 // For Windows, we need the PDF DLL to render the output PDF to a DC.
1171 HMODULE pdf_module
= GetModuleHandle(L
"pdf.dll");
1174 RenderPDFPageToDCProc render_proc
=
1175 reinterpret_cast<RenderPDFPageToDCProc
>(
1176 GetProcAddress(pdf_module
, "RenderPDFPageToDC"));
1179 #endif // defined(OS_WIN)
1182 #if defined(OS_LINUX)
1183 // On Linux we just set the final bits in the native metafile.
1184 printing::NativeMetafile
* metafile
=
1185 printing::NativeMetafileSkiaWrapper::GetMetafileFromCanvas(canvas
);
1186 DCHECK(metafile
!= NULL
);
1188 ret
= metafile
->InitFromData(buffer
->mapped_buffer(), buffer
->size());
1189 #elif defined(OS_MACOSX)
1190 // Create a PDF metafile and render from there into the passed in context.
1191 scoped_ptr
<printing::NativeMetafile
> metafile(
1192 printing::NativeMetafileFactory::CreateFromData(buffer
->mapped_buffer(),
1194 if (metafile
.get() != NULL
) {
1195 // Flip the transform.
1196 CGContextSaveGState(canvas
);
1197 CGContextTranslateCTM(canvas
, 0,
1198 current_print_settings_
.printable_area
.size
.height
);
1199 CGContextScaleCTM(canvas
, 1.0, -1.0);
1201 page_rect
.origin
.x
= current_print_settings_
.printable_area
.point
.x
;
1202 page_rect
.origin
.y
= current_print_settings_
.printable_area
.point
.y
;
1203 page_rect
.size
.width
= current_print_settings_
.printable_area
.size
.width
;
1204 page_rect
.size
.height
= current_print_settings_
.printable_area
.size
.height
;
1206 ret
= metafile
->RenderPage(1, canvas
, page_rect
, true, false, true, true);
1207 CGContextRestoreGState(canvas
);
1209 #elif defined(OS_WIN)
1210 // On Windows, we now need to render the PDF to the DC that backs the
1212 skia::VectorPlatformDevice
& device
=
1213 static_cast<skia::VectorPlatformDevice
&>(
1214 canvas
->getTopPlatformDevice());
1215 HDC dc
= device
.getBitmapDC();
1216 gfx::Size size_in_pixels
;
1217 size_in_pixels
.set_width(
1218 printing::ConvertUnit(current_print_settings_
.printable_area
.size
.width
,
1219 static_cast<int>(printing::kPointsPerInch
),
1220 current_print_settings_
.dpi
));
1221 size_in_pixels
.set_height(
1222 printing::ConvertUnit(current_print_settings_
.printable_area
.size
.height
,
1223 static_cast<int>(printing::kPointsPerInch
),
1224 current_print_settings_
.dpi
));
1225 // We need to render using the actual printer DPI (rendering to a smaller
1226 // set of pixels leads to a blurry output). However, we need to counter the
1227 // scaling up that will happen in the browser.
1229 xform
.eM11
= xform
.eM22
= static_cast<float>(printing::kPointsPerInch
) /
1230 static_cast<float>(current_print_settings_
.dpi
);
1231 ModifyWorldTransform(dc
, &xform
, MWT_LEFTMULTIPLY
);
1233 ret
= render_proc(buffer
->mapped_buffer(), buffer
->size(), 0, dc
,
1234 current_print_settings_
.dpi
, current_print_settings_
.dpi
,
1235 0, 0, size_in_pixels
.width(),
1236 size_in_pixels
.height(), true, false, true, true);
1237 #endif // defined(OS_WIN)
1242 bool PluginInstance::PrintRasterOutput(PP_Resource print_output
,
1243 WebKit::WebCanvas
* canvas
) {
1244 scoped_refptr
<PPB_ImageData_Impl
> image(
1245 Resource::GetAs
<PPB_ImageData_Impl
>(print_output
));
1246 if (!image
.get() || !image
->is_mapped())
1249 const SkBitmap
* bitmap
= image
->GetMappedBitmap();
1253 // Draw the printed image into the supplied canvas.
1255 src_rect
.set(0, 0, bitmap
->width(), bitmap
->height());
1258 SkIntToScalar(current_print_settings_
.printable_area
.point
.x
),
1259 SkIntToScalar(current_print_settings_
.printable_area
.point
.y
),
1260 SkIntToScalar(current_print_settings_
.printable_area
.point
.x
+
1261 current_print_settings_
.printable_area
.size
.width
),
1262 SkIntToScalar(current_print_settings_
.printable_area
.point
.y
+
1263 current_print_settings_
.printable_area
.size
.height
));
1264 bool draw_to_canvas
= true;
1265 gfx::Rect dest_rect_gfx
;
1266 dest_rect_gfx
.set_x(current_print_settings_
.printable_area
.point
.x
);
1267 dest_rect_gfx
.set_y(current_print_settings_
.printable_area
.point
.y
);
1268 dest_rect_gfx
.set_width(current_print_settings_
.printable_area
.size
.width
);
1269 dest_rect_gfx
.set_height(current_print_settings_
.printable_area
.size
.height
);
1272 // Since this is a raster output, the size of the bitmap can be
1273 // huge (especially at high printer DPIs). On Windows, this can
1274 // result in a HUGE EMF (on Mac and Linux the output goes to PDF
1275 // which appears to Flate compress the bitmap). So, if this bitmap
1276 // is larger than 20 MB, we save the bitmap as a JPEG into the EMF
1277 // DC. Note: We chose JPEG over PNG because JPEG compression seems
1278 // way faster (about 4 times faster).
1279 static const int kCompressionThreshold
= 20 * 1024 * 1024;
1280 if (bitmap
->getSize() > kCompressionThreshold
) {
1281 DrawJPEGToPlatformDC(*bitmap
, dest_rect_gfx
, canvas
);
1282 draw_to_canvas
= false;
1284 #endif // defined(OS_WIN)
1285 #if defined(OS_MACOSX)
1286 draw_to_canvas
= false;
1287 DrawSkBitmapToCanvas(*bitmap
, canvas
, dest_rect_gfx
,
1288 current_print_settings_
.printable_area
.size
.height
);
1289 // See comments in the header file.
1290 last_printed_page_
= image
;
1291 #else // defined(OS_MACOSX)
1293 canvas
->drawBitmapRect(*bitmap
, &src_rect
, dest_rect
);
1294 #endif // defined(OS_MACOSX)
1299 bool PluginInstance::DrawJPEGToPlatformDC(
1300 const SkBitmap
& bitmap
,
1301 const gfx::Rect
& printable_area
,
1302 WebKit::WebCanvas
* canvas
) {
1303 skia::VectorPlatformDevice
& device
=
1304 static_cast<skia::VectorPlatformDevice
&>(
1305 canvas
->getTopPlatformDevice());
1306 HDC dc
= device
.getBitmapDC();
1307 // TODO(sanjeevr): This is a temporary hack. If we output a JPEG
1308 // to the EMF, the EnumEnhMetaFile call fails in the browser
1309 // process. The failure also happens if we output nothing here.
1310 // We need to investigate the reason for this failure and fix it.
1311 // In the meantime this temporary hack of drawing an empty
1312 // rectangle in the DC gets us by.
1313 Rectangle(dc
, 0, 0, 0, 0);
1315 // Ideally we should add JPEG compression to the VectorPlatformDevice class
1316 // However, Skia currently has no JPEG compression code and we cannot
1317 // depend on gfx/jpeg_codec.h in Skia. So we do the compression here.
1318 SkAutoLockPixels
lock(bitmap
);
1319 DCHECK(bitmap
.getConfig() == SkBitmap::kARGB_8888_Config
);
1320 const uint32_t* pixels
=
1321 static_cast<const uint32_t*>(bitmap
.getPixels());
1322 std::vector
<unsigned char> compressed_image
;
1323 base::TimeTicks start_time
= base::TimeTicks::Now();
1324 bool encoded
= gfx::JPEGCodec::Encode(
1325 reinterpret_cast<const unsigned char*>(pixels
),
1326 gfx::JPEGCodec::FORMAT_BGRA
, bitmap
.width(), bitmap
.height(),
1327 static_cast<int>(bitmap
.rowBytes()), 100, &compressed_image
);
1328 UMA_HISTOGRAM_TIMES("PepperPluginPrint.RasterBitmapCompressTime",
1329 base::TimeTicks::Now() - start_time
);
1334 BITMAPINFOHEADER bmi
= {0};
1335 gfx::CreateBitmapHeader(bitmap
.width(), bitmap
.height(), &bmi
);
1336 bmi
.biCompression
= BI_JPEG
;
1337 bmi
.biSizeImage
= compressed_image
.size();
1338 bmi
.biHeight
= -bmi
.biHeight
;
1339 StretchDIBits(dc
, printable_area
.x(), printable_area
.y(),
1340 printable_area
.width(), printable_area
.height(),
1341 0, 0, bitmap
.width(), bitmap
.height(),
1342 &compressed_image
.front(),
1343 reinterpret_cast<const BITMAPINFO
*>(&bmi
),
1344 DIB_RGB_COLORS
, SRCCOPY
);
1349 #if defined(OS_MACOSX)
1350 void PluginInstance::DrawSkBitmapToCanvas(
1351 const SkBitmap
& bitmap
, WebKit::WebCanvas
* canvas
,
1352 const gfx::Rect
& dest_rect
,
1353 int canvas_height
) {
1354 SkAutoLockPixels
lock(bitmap
);
1355 DCHECK(bitmap
.getConfig() == SkBitmap::kARGB_8888_Config
);
1356 base::mac::ScopedCFTypeRef
<CGDataProviderRef
> data_provider(
1357 CGDataProviderCreateWithData(
1358 NULL
, bitmap
.getAddr32(0, 0),
1359 bitmap
.rowBytes() * bitmap
.height(), NULL
));
1360 base::mac::ScopedCFTypeRef
<CGImageRef
> image(
1362 bitmap
.width(), bitmap
.height(),
1363 8, 32, bitmap
.rowBytes(),
1364 base::mac::GetSystemColorSpace(),
1365 kCGImageAlphaPremultipliedFirst
| kCGBitmapByteOrder32Host
,
1366 data_provider
, NULL
, false, kCGRenderingIntentDefault
));
1368 // Flip the transform
1369 CGContextSaveGState(canvas
);
1370 CGContextTranslateCTM(canvas
, 0, canvas_height
);
1371 CGContextScaleCTM(canvas
, 1.0, -1.0);
1374 bounds
.origin
.x
= dest_rect
.x();
1375 bounds
.origin
.y
= canvas_height
- dest_rect
.y() - dest_rect
.height();
1376 bounds
.size
.width
= dest_rect
.width();
1377 bounds
.size
.height
= dest_rect
.height();
1379 CGContextDrawImage(canvas
, bounds
, image
);
1380 CGContextRestoreGState(canvas
);
1382 #endif // defined(OS_MACOSX)
1384 PPB_Graphics2D_Impl
* PluginInstance::bound_graphics_2d() const {
1385 if (bound_graphics_
.get() == NULL
)
1388 return bound_graphics_
->Cast
<PPB_Graphics2D_Impl
>();
1391 PPB_Surface3D_Impl
* PluginInstance::bound_graphics_3d() const {
1392 if (bound_graphics_
.get() == NULL
)
1395 return bound_graphics_
->Cast
<PPB_Surface3D_Impl
>();
1398 void PluginInstance::setBackingTextureId(unsigned int id
) {
1399 // If we have a full-screen container_ then the plugin is fullscreen,
1400 // and the parent context is not the one for the browser page, but for the
1401 // full-screen window, and so the parent texture ID doesn't correspond to
1402 // anything in the page's context.
1404 // TODO(alokp): It would be better at some point to have the equivalent
1405 // in the FullscreenContainer so that we don't need to poll
1406 if (fullscreen_container_
)
1410 container_
->setBackingTextureId(id
);
1413 void PluginInstance::AddPluginObject(PluginObject
* plugin_object
) {
1414 DCHECK(live_plugin_objects_
.find(plugin_object
) ==
1415 live_plugin_objects_
.end());
1416 live_plugin_objects_
.insert(plugin_object
);
1419 void PluginInstance::RemovePluginObject(PluginObject
* plugin_object
) {
1420 // Don't actually verify that the object is in the set since during module
1421 // deletion we'll be in the process of freeing them.
1422 live_plugin_objects_
.erase(plugin_object
);
1425 void PluginInstance::AddNPObjectVar(ObjectVar
* object_var
) {
1426 DCHECK(np_object_to_object_var_
.find(object_var
->np_object()) ==
1427 np_object_to_object_var_
.end()) << "ObjectVar already in map";
1428 np_object_to_object_var_
[object_var
->np_object()] = object_var
;
1431 void PluginInstance::RemoveNPObjectVar(ObjectVar
* object_var
) {
1432 NPObjectToObjectVarMap::iterator found
=
1433 np_object_to_object_var_
.find(object_var
->np_object());
1434 if (found
== np_object_to_object_var_
.end()) {
1435 NOTREACHED() << "ObjectVar not registered.";
1438 if (found
->second
!= object_var
) {
1439 NOTREACHED() << "ObjectVar doesn't match.";
1442 np_object_to_object_var_
.erase(found
);
1445 ObjectVar
* PluginInstance::ObjectVarForNPObject(NPObject
* np_object
) const {
1446 NPObjectToObjectVarMap::const_iterator found
=
1447 np_object_to_object_var_
.find(np_object
);
1448 if (found
== np_object_to_object_var_
.end())
1450 return found
->second
;
1453 bool PluginInstance::IsFullPagePlugin() const {
1454 WebFrame
* frame
= container()->element().document().frame();
1455 return frame
->view()->mainFrame()->document().isPluginDocument();
1458 } // namespace ppapi
1459 } // namespace webkit