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/cpp/graphics_2d.h"
6#include "ppapi/cpp/image_data.h"
7#include "ppapi/cpp/instance.h"
8#include "ppapi/cpp/logging.h"
9#include "ppapi/cpp/module.h"
10#include "ppapi/cpp/private/flash.h"
11#include "ppapi/cpp/rect.h"
12#include "ppapi/cpp/size.h"
13#include "ppapi/utility/completion_callback_factory.h"
14
15const int32_t kTimerInterval = 200;
16
17class MyInstance : public pp::Instance {
18 public:
19  explicit MyInstance(PP_Instance instance)
20      : pp::Instance(instance),
21        callback_factory_(this),
22        pending_paint_(false),
23        waiting_for_flush_completion_(false) {
24  }
25  virtual ~MyInstance() {
26  }
27
28  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
29    ScheduleNextTimer();
30    return true;
31  }
32
33  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
34    if (position.size() != size_) {
35      size_ = position.size();
36      device_context_ = pp::Graphics2D(this, size_, false);
37      if (!BindGraphics(device_context_))
38        return;
39    }
40
41    Paint();
42  }
43
44 private:
45  void ScheduleNextTimer() {
46    pp::Module::Get()->core()->CallOnMainThread(
47        kTimerInterval,
48        callback_factory_.NewCallback(&MyInstance::OnTimer),
49        0);
50  }
51
52  void OnTimer(int32_t) {
53    ScheduleNextTimer();
54    Paint();
55  }
56
57  void DidFlush(int32_t result) {
58    waiting_for_flush_completion_ = false;
59    if (pending_paint_)
60      Paint();
61  }
62
63  void Paint() {
64    if (waiting_for_flush_completion_) {
65      pending_paint_ = true;
66      return;
67    }
68
69    pending_paint_ = false;
70
71    if (size_.IsEmpty())
72      return;  // Nothing to do.
73
74    pp::ImageData image = PaintImage(size_);
75    if (!image.is_null()) {
76      device_context_.ReplaceContents(&image);
77      waiting_for_flush_completion_ = true;
78      device_context_.Flush(
79          callback_factory_.NewCallback(&MyInstance::DidFlush));
80    }
81  }
82
83  pp::ImageData PaintImage(const pp::Size& size) {
84    pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL, size, false);
85    if (image.is_null())
86      return image;
87
88    pp::Rect rect(size.width() / 8, size.height() / 4,
89                  3 * size.width() / 4, size.height() / 2);
90    uint32_t fill_color = pp::flash::Flash::IsRectTopmost(this, rect) ?
91        0xff00ff00 : 0xffff0000;
92
93    for (int y = 0; y < size.height(); y++) {
94      for (int x = 0; x < size.width(); x++)
95        *image.GetAddr32(pp::Point(x, y)) = fill_color;
96    }
97
98    for (int x = rect.x(); x < rect.x() + rect.width(); x++) {
99      *image.GetAddr32(pp::Point(x, rect.y())) = 0xff202020;
100      *image.GetAddr32(pp::Point(x, rect.y() + rect.height() - 1)) = 0xff202020;
101    }
102    for (int y = rect.y(); y < rect.y() + rect.height(); y++) {
103      *image.GetAddr32(pp::Point(rect.x(), y)) = 0xff202020;
104      *image.GetAddr32(pp::Point(rect.x() + rect.width() - 1, y)) = 0xff202020;
105    }
106
107    return image;
108  }
109
110  pp::CompletionCallbackFactory<MyInstance> callback_factory_;
111
112  // Painting stuff.
113  pp::Size size_;
114  pp::Graphics2D device_context_;
115  bool pending_paint_;
116  bool waiting_for_flush_completion_;
117};
118
119class MyModule : public pp::Module {
120 public:
121  virtual pp::Instance* CreateInstance(PP_Instance instance) {
122    return new MyInstance(instance);
123  }
124};
125
126namespace pp {
127
128// Factory function for your specialization of the Module object.
129Module* CreateModule() {
130  return new MyModule();
131}
132
133}  // namespace pp
134