1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/graphics_2d_resource.h"
6
7#include "ppapi/c/pp_bool.h"
8#include "ppapi/c/pp_point.h"
9#include "ppapi/c/pp_rect.h"
10#include "ppapi/c/pp_resource.h"
11#include "ppapi/c/pp_size.h"
12#include "ppapi/c/ppb_graphics_2d.h"
13#include "ppapi/proxy/dispatch_reply_message.h"
14#include "ppapi/proxy/plugin_dispatcher.h"
15#include "ppapi/proxy/ppapi_messages.h"
16#include "ppapi/shared_impl/ppapi_globals.h"
17#include "ppapi/shared_impl/resource_tracker.h"
18#include "ppapi/shared_impl/tracked_callback.h"
19#include "ppapi/thunk/enter.h"
20#include "ppapi/thunk/ppb_image_data_api.h"
21
22namespace ppapi {
23namespace proxy {
24
25Graphics2DResource::Graphics2DResource(Connection connection,
26                                       PP_Instance instance,
27                                       const PP_Size& size,
28                                       PP_Bool is_always_opaque)
29    : PluginResource(connection, instance),
30      size_(size),
31      is_always_opaque_(is_always_opaque),
32      scale_(1.0f) {
33  // These checks are copied from PPB_ImageData_Impl::Init to make tests passed.
34  // Let's remove/refactor this when start to refactor ImageData.
35  bool bad_args = size.width <= 0 || size.height <= 0 ||
36      static_cast<int64>(size.width) * static_cast<int64>(size.height) >=
37          std::numeric_limits<int32>::max() / 4;
38  if (!bad_args && !sent_create_to_renderer()) {
39    SendCreate(RENDERER,
40        PpapiHostMsg_Graphics2D_Create(size, is_always_opaque));
41  }
42}
43
44Graphics2DResource::~Graphics2DResource() {
45}
46
47PP_Bool Graphics2DResource::Describe(PP_Size* size, PP_Bool* is_always_opaque) {
48  *size = size_;
49  *is_always_opaque = is_always_opaque_;
50  return PP_TRUE;
51}
52
53thunk::PPB_Graphics2D_API* Graphics2DResource::AsPPB_Graphics2D_API() {
54  return this;
55}
56
57void Graphics2DResource::PaintImageData(PP_Resource image_data,
58                                        const PP_Point* top_left,
59                                        const PP_Rect* src_rect) {
60  Resource* image_object =
61      PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data);
62  if (!image_object || pp_instance() != image_object->pp_instance()) {
63    Log(PP_LOGLEVEL_ERROR,
64        "Graphics2DResource.PaintImageData: Bad image resource.");
65    return;
66  }
67
68  PP_Rect dummy;
69  memset(&dummy, 0, sizeof(PP_Rect));
70  Post(RENDERER, PpapiHostMsg_Graphics2D_PaintImageData(
71      image_object->host_resource(), *top_left,
72      !!src_rect, src_rect ? *src_rect : dummy));
73}
74
75void Graphics2DResource::Scroll(const PP_Rect* clip_rect,
76                                const PP_Point* amount) {
77  PP_Rect dummy;
78  memset(&dummy, 0, sizeof(PP_Rect));
79  Post(RENDERER, PpapiHostMsg_Graphics2D_Scroll(
80      !!clip_rect, clip_rect ? *clip_rect : dummy, *amount));
81}
82
83void Graphics2DResource::ReplaceContents(PP_Resource image_data) {
84  thunk::EnterResourceNoLock<thunk::PPB_ImageData_API> enter_image(
85      image_data, true);
86  if (enter_image.failed())
87    return;
88
89  // Check that the PP_Instance matches.
90  Resource* image_object =
91      PpapiGlobals::Get()->GetResourceTracker()->GetResource(image_data);
92  if (!image_object || pp_instance() != image_object->pp_instance()) {
93    Log(PP_LOGLEVEL_ERROR,
94        "Graphics2DResource.PaintImageData: Bad image resource.");
95    return;
96  }
97  enter_image.object()->SetIsCandidateForReuse();
98
99  Post(RENDERER, PpapiHostMsg_Graphics2D_ReplaceContents(
100      image_object->host_resource()));
101}
102
103PP_Bool Graphics2DResource::SetScale(float scale) {
104  if (scale <= 0.0f)
105    return PP_FALSE;
106  Post(RENDERER, PpapiHostMsg_Graphics2D_SetScale(scale));
107  scale_ = scale;
108  return PP_TRUE;
109}
110
111float Graphics2DResource::GetScale() {
112  return scale_;
113}
114
115int32_t Graphics2DResource::Flush(scoped_refptr<TrackedCallback> callback) {
116  // If host is not even created, return failure immediately.  This can happen
117  // when failed to initialize (in constructor).
118  if (!sent_create_to_renderer())
119    return PP_ERROR_FAILED;
120
121  if (TrackedCallback::IsPending(current_flush_callback_))
122    return PP_ERROR_INPROGRESS;  // Can't have >1 flush pending.
123  current_flush_callback_ = callback;
124
125  std::vector<ui::LatencyInfo> latency_info;
126  PpapiGlobals::Get()->TransferLatencyInfoTo(&latency_info, pp_instance());
127
128  Call<PpapiPluginMsg_Graphics2D_FlushAck>(
129      RENDERER,
130      PpapiHostMsg_Graphics2D_Flush(latency_info),
131      base::Bind(&Graphics2DResource::OnPluginMsgFlushACK, this));
132  return PP_OK_COMPLETIONPENDING;
133}
134
135bool Graphics2DResource::ReadImageData(PP_Resource image,
136                                       const PP_Point* top_left) {
137  if (!top_left)
138    return false;
139  int32_t result = SyncCall<PpapiPluginMsg_Graphics2D_ReadImageDataAck>(
140      RENDERER,
141      PpapiHostMsg_Graphics2D_ReadImageData(image, *top_left));
142  return result == PP_OK;
143}
144
145void Graphics2DResource::OnPluginMsgFlushACK(
146    const ResourceMessageReplyParams& params) {
147  current_flush_callback_->Run(params.result());
148}
149
150}  // namespace proxy
151}  // namespace ppapi
152