blob: 010a9140d719cfa514b73988793500f3a9935a20 [file] [log] [blame]
jvanverth9f372462016-04-06 06:08:59 -07001/*
2* Copyright 2016 Google Inc.
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
7
jvanverth34524262016-05-04 13:49:13 -07008#include "Viewer.h"
jvanverth9f372462016-04-06 06:08:59 -07009
jvanverth2bb3b6d2016-04-08 07:24:09 -070010#include "GMSlide.h"
liyuqian6f163d22016-06-13 12:26:45 -070011#include "ImageSlide.h"
jvanverthc7027ab2016-06-16 09:52:35 -070012#include "SampleSlide.h"
jvanverth2bb3b6d2016-04-08 07:24:09 -070013#include "SKPSlide.h"
jvanverth9f372462016-04-06 06:08:59 -070014
jvanverth2bb3b6d2016-04-08 07:24:09 -070015#include "SkCanvas.h"
16#include "SkCommonFlags.h"
liyuqian74959a12016-06-16 14:10:34 -070017#include "SkDashPathEffect.h"
liyuqian6f163d22016-06-13 12:26:45 -070018#include "SkMetaData.h"
jvanverth2bb3b6d2016-04-08 07:24:09 -070019#include "SkOSFile.h"
20#include "SkRandom.h"
21#include "SkStream.h"
liyuqian74959a12016-06-16 14:10:34 -070022#include "SkSurface.h"
jvanverth9f372462016-04-06 06:08:59 -070023
jvanverth34524262016-05-04 13:49:13 -070024using namespace sk_app;
25
jvanverth9f372462016-04-06 06:08:59 -070026Application* Application::Create(int argc, char** argv, void* platformData) {
jvanverth34524262016-05-04 13:49:13 -070027 return new Viewer(argc, argv, platformData);
jvanverth9f372462016-04-06 06:08:59 -070028}
29
jvanverth9f372462016-04-06 06:08:59 -070030static void on_paint_handler(SkCanvas* canvas, void* userData) {
jvanverth34524262016-05-04 13:49:13 -070031 Viewer* vv = reinterpret_cast<Viewer*>(userData);
jvanverth9f372462016-04-06 06:08:59 -070032
33 return vv->onPaint(canvas);
34}
35
jvanverth814e38d2016-06-06 08:48:47 -070036static bool on_touch_handler(intptr_t owner, Window::InputState state, float x, float y, void* userData)
liyuqiand3cdbca2016-05-17 12:44:20 -070037{
38 Viewer* viewer = reinterpret_cast<Viewer*>(userData);
39
40 return viewer->onTouch(owner, state, x, y);
41}
42
liyuqiane5a6cd92016-05-27 08:52:52 -070043static void on_ui_state_changed_handler(const SkString& stateName, const SkString& stateValue, void* userData) {
44 Viewer* viewer = reinterpret_cast<Viewer*>(userData);
45
46 return viewer->onUIStateChanged(stateName, stateValue);
47}
48
49DEFINE_bool2(fullscreen, f, true, "Run fullscreen.");
egdanielf533f112016-06-13 11:30:10 -070050DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder.");
jvanverth2bb3b6d2016-04-08 07:24:09 -070051DEFINE_string2(match, m, nullptr,
52 "[~][^]substring[$] [...] of bench name to run.\n"
53 "Multiple matches may be separated by spaces.\n"
54 "~ causes a matching bench to always be skipped\n"
55 "^ requires the start of the bench to match\n"
56 "$ requires the end of the bench to match\n"
57 "^ and $ requires an exact match\n"
58 "If a bench does not match any list entry,\n"
59 "it is skipped unless some list entry starts with ~");
liyuqian71491dc2016-06-09 12:02:34 -070060#ifdef SK_BUILD_FOR_ANDROID
liyuqian6f163d22016-06-13 12:26:45 -070061DEFINE_string(skps, "/data/local/tmp/skia", "Directory to read skps from.");
62DEFINE_string(jpgs, "/data/local/tmp/skia", "Directory to read jpgs from.");
liyuqian71491dc2016-06-09 12:02:34 -070063DEFINE_bool(vulkan, false, "Run with Vulkan.");
64#else
liyuqian6f163d22016-06-13 12:26:45 -070065DEFINE_string(skps, "skps", "Directory to read skps from.");
66DEFINE_string(jpgs, "jpgs", "Directory to read jpgs from.");
jvanverth85f758c2016-05-27 06:47:08 -070067DEFINE_bool(vulkan, true, "Run with Vulkan.");
liyuqian71491dc2016-06-09 12:02:34 -070068#endif
jvanverth2bb3b6d2016-04-08 07:24:09 -070069
jvanverthaf236b52016-05-20 06:01:06 -070070const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
71 " [OpenGL]",
liyuqiand94ad582016-06-07 14:22:37 -070072 " [Vulkan]",
73 " [Raster]"
jvanverthaf236b52016-05-20 06:01:06 -070074};
75
liyuqiane5a6cd92016-05-27 08:52:52 -070076const char* kName = "name";
77const char* kValue = "value";
78const char* kOptions = "options";
79const char* kSlideStateName = "Slide";
80const char* kBackendStateName = "Backend";
liyuqianb73c24b2016-06-03 08:47:23 -070081const char* kSoftkeyStateName = "Softkey";
82const char* kSoftkeyHint = "Please select a softkey";
liyuqian1f508fd2016-06-07 06:57:40 -070083const char* kFpsStateName = "FPS";
liyuqian6f163d22016-06-13 12:26:45 -070084const char* kSplitScreenStateName = "Split screen";
85const char* kON = "ON";
86const char* kOFF = "OFF";
liyuqiane5a6cd92016-05-27 08:52:52 -070087
jvanverth34524262016-05-04 13:49:13 -070088Viewer::Viewer(int argc, char** argv, void* platformData)
jvanverthc265a922016-04-08 12:51:45 -070089 : fCurrentMeasurement(0)
90 , fDisplayStats(false)
liyuqian6f163d22016-06-13 12:26:45 -070091 , fSplitScreen(false)
egdaniel963632f2016-06-15 14:23:40 -070092 , fBackendType(sk_app::Window::kVulkan_BackendType)
egdaniel2a0bb0a2016-04-11 08:30:40 -070093 , fZoomCenterX(0.0f)
94 , fZoomCenterY(0.0f)
95 , fZoomLevel(0.0f)
96 , fZoomScale(SK_Scalar1)
jvanverthc265a922016-04-08 12:51:45 -070097{
jvanverth3d6ed3a2016-04-07 11:09:51 -070098 memset(fMeasurements, 0, sizeof(fMeasurements));
jvanverth9f372462016-04-06 06:08:59 -070099
jvanverth2bb3b6d2016-04-08 07:24:09 -0700100 SkDebugf("Command line arguments: ");
101 for (int i = 1; i < argc; ++i) {
102 SkDebugf("%s ", argv[i]);
103 }
104 SkDebugf("\n");
105
106 SkCommandLineFlags::Parse(argc, argv);
107
jvanverth85f758c2016-05-27 06:47:08 -0700108 fBackendType = FLAGS_vulkan ? sk_app::Window::kVulkan_BackendType
109 : sk_app::Window::kNativeGL_BackendType;
egdaniel963632f2016-06-15 14:23:40 -0700110
jvanverth9f372462016-04-06 06:08:59 -0700111 fWindow = Window::CreateNativeWindow(platformData);
jvanverthaf236b52016-05-20 06:01:06 -0700112 fWindow->attach(fBackendType, DisplayParams());
jvanverth9f372462016-04-06 06:08:59 -0700113
114 // register callbacks
brianosman622c8d52016-05-10 06:50:49 -0700115 fCommands.attach(fWindow);
jvanverth9f372462016-04-06 06:08:59 -0700116 fWindow->registerPaintFunc(on_paint_handler, this);
liyuqiand3cdbca2016-05-17 12:44:20 -0700117 fWindow->registerTouchFunc(on_touch_handler, this);
liyuqiane5a6cd92016-05-27 08:52:52 -0700118 fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this);
jvanverth9f372462016-04-06 06:08:59 -0700119
brianosman622c8d52016-05-10 06:50:49 -0700120 // add key-bindings
121 fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() {
122 this->fDisplayStats = !this->fDisplayStats;
123 fWindow->inval();
124 });
125 fCommands.addCommand('c', "Modes", "Toggle sRGB color mode", [this]() {
126 DisplayParams params = fWindow->getDisplayParams();
brianosmanb109b8c2016-06-16 13:03:24 -0700127 params.fColorSpace = (nullptr == params.fColorSpace)
128 ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr;
brianosman622c8d52016-05-10 06:50:49 -0700129 fWindow->setDisplayParams(params);
130 this->updateTitle();
131 fWindow->inval();
132 });
133 fCommands.addCommand(Window::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
134 int previousSlide = fCurrentSlide;
135 fCurrentSlide++;
136 if (fCurrentSlide >= fSlides.count()) {
137 fCurrentSlide = 0;
138 }
139 this->setupCurrentSlide(previousSlide);
140 });
141 fCommands.addCommand(Window::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
142 int previousSlide = fCurrentSlide;
143 fCurrentSlide--;
144 if (fCurrentSlide < 0) {
145 fCurrentSlide = fSlides.count() - 1;
146 }
147 this->setupCurrentSlide(previousSlide);
148 });
149 fCommands.addCommand(Window::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
150 this->changeZoomLevel(1.f / 32.f);
151 fWindow->inval();
152 });
153 fCommands.addCommand(Window::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
154 this->changeZoomLevel(-1.f / 32.f);
155 fWindow->inval();
156 });
jvanverth85f758c2016-05-27 06:47:08 -0700157#if 0 // this doesn't seem to work on any platform right now
jvanverthaf236b52016-05-20 06:01:06 -0700158#ifndef SK_BUILD_FOR_ANDROID
159 fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() {
160 fWindow->detach();
161
162 if (sk_app::Window::kVulkan_BackendType == fBackendType) {
163 fBackendType = sk_app::Window::kNativeGL_BackendType;
164 }
jvanverth85f758c2016-05-27 06:47:08 -0700165 // TODO: get Vulkan -> OpenGL working on Windows without swapchain creation failure
jvanverthaf236b52016-05-20 06:01:06 -0700166 //else if (sk_app::Window::kNativeGL_BackendType == fBackendType) {
167 // fBackendType = sk_app::Window::kVulkan_BackendType;
168 //}
169
170 fWindow->attach(fBackendType, DisplayParams());
171 this->updateTitle();
jvanverth85f758c2016-05-27 06:47:08 -0700172 fWindow->inval();
jvanverthaf236b52016-05-20 06:01:06 -0700173 });
174#endif
jvanverth85f758c2016-05-27 06:47:08 -0700175#endif
brianosman622c8d52016-05-10 06:50:49 -0700176
jvanverth2bb3b6d2016-04-08 07:24:09 -0700177 // set up slides
178 this->initSlides();
179
djsollen12d62a72016-04-21 07:59:44 -0700180 fAnimTimer.run();
181
jvanverth2bb3b6d2016-04-08 07:24:09 -0700182 // set up first frame
jvanverth2bb3b6d2016-04-08 07:24:09 -0700183 fCurrentSlide = 0;
jvanverthc265a922016-04-08 12:51:45 -0700184 setupCurrentSlide(-1);
jvanverthc265a922016-04-08 12:51:45 -0700185
jvanverth9f372462016-04-06 06:08:59 -0700186 fWindow->show();
187}
188
jvanverth34524262016-05-04 13:49:13 -0700189void Viewer::initSlides() {
liyuqian1f508fd2016-06-07 06:57:40 -0700190 fAllSlideNames = Json::Value(Json::arrayValue);
191
jvanverth2bb3b6d2016-04-08 07:24:09 -0700192 const skiagm::GMRegistry* gms(skiagm::GMRegistry::Head());
193 while (gms) {
194 SkAutoTDelete<skiagm::GM> gm(gms->factory()(nullptr));
195
196 if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) {
197 sk_sp<Slide> slide(new GMSlide(gm.release()));
198 fSlides.push_back(slide);
199 }
200
201 gms = gms->next();
202 }
203
204 // reverse array
205 for (int i = 0; i < fSlides.count()/2; ++i) {
206 sk_sp<Slide> temp = fSlides[i];
207 fSlides[i] = fSlides[fSlides.count() - i - 1];
208 fSlides[fSlides.count() - i - 1] = temp;
209 }
210
jvanverthc7027ab2016-06-16 09:52:35 -0700211 // samples
212 const SkViewRegister* reg = SkViewRegister::Head();
213 while (reg) {
214 sk_sp<Slide> slide(new SampleSlide(reg->factory()));
215 fSlides.push_back(slide);
216 reg = reg->next();
217 }
218
jvanverth2bb3b6d2016-04-08 07:24:09 -0700219 // SKPs
220 for (int i = 0; i < FLAGS_skps.count(); i++) {
221 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
jvanverthc265a922016-04-08 12:51:45 -0700222 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
223 continue;
224 }
225
jvanverth2bb3b6d2016-04-08 07:24:09 -0700226 SkString path(FLAGS_skps[i]);
jvanverthc265a922016-04-08 12:51:45 -0700227 sk_sp<SKPSlide> slide(new SKPSlide(SkOSPath::Basename(path.c_str()), path));
jvanverth2bb3b6d2016-04-08 07:24:09 -0700228 if (slide) {
229 fSlides.push_back(slide);
230 }
231 } else {
232 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
jvanverthc265a922016-04-08 12:51:45 -0700233 SkString skpName;
234 while (it.next(&skpName)) {
235 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, skpName.c_str())) {
236 continue;
237 }
238
239 SkString path = SkOSPath::Join(FLAGS_skps[i], skpName.c_str());
240 sk_sp<SKPSlide> slide(new SKPSlide(skpName, path));
jvanverth2bb3b6d2016-04-08 07:24:09 -0700241 if (slide) {
242 fSlides.push_back(slide);
243 }
244 }
245 }
246 }
liyuqian6f163d22016-06-13 12:26:45 -0700247
248 // JPGs
249 for (int i = 0; i < FLAGS_jpgs.count(); i++) {
250 SkOSFile::Iter it(FLAGS_jpgs[i], ".jpg");
251 SkString jpgName;
252 while (it.next(&jpgName)) {
253 SkString path = SkOSPath::Join(FLAGS_jpgs[i], jpgName.c_str());
254 sk_sp<ImageSlide> slide(new ImageSlide(jpgName, path));
255 if (slide) {
256 fSlides.push_back(slide);
257 }
258 }
259 }
jvanverth2bb3b6d2016-04-08 07:24:09 -0700260}
261
262
jvanverth34524262016-05-04 13:49:13 -0700263Viewer::~Viewer() {
jvanverth9f372462016-04-06 06:08:59 -0700264 fWindow->detach();
265 delete fWindow;
266}
267
brianosman05de2162016-05-06 13:28:57 -0700268void Viewer::updateTitle() {
jvanverth34524262016-05-04 13:49:13 -0700269 SkString title("Viewer: ");
jvanverthc265a922016-04-08 12:51:45 -0700270 title.append(fSlides[fCurrentSlide]->getName());
brianosmanb109b8c2016-06-16 13:03:24 -0700271
272 // TODO: For now, any color-space on the window means sRGB
273 if (fWindow->getDisplayParams().fColorSpace) {
brianosman05de2162016-05-06 13:28:57 -0700274 title.append(" sRGB");
275 }
jvanverthaf236b52016-05-20 06:01:06 -0700276 title.append(kBackendTypeStrings[fBackendType]);
brianosman05de2162016-05-06 13:28:57 -0700277 fWindow->setTitle(title.c_str());
278}
279
280void Viewer::setupCurrentSlide(int previousSlide) {
liyuqiane5a6cd92016-05-27 08:52:52 -0700281 if (fCurrentSlide == previousSlide) {
282 return; // no change; do nothing
283 }
284
liyuqian6f163d22016-06-13 12:26:45 -0700285 // prepare dimensions for image slides
jvanverthc7027ab2016-06-16 09:52:35 -0700286 fSlides[fCurrentSlide]->load(SkIntToScalar(fWindow->width()), SkIntToScalar(fWindow->height()));
liyuqian6f163d22016-06-13 12:26:45 -0700287
liyuqiane46e4f02016-05-20 07:32:19 -0700288 fGesture.reset();
289 fDefaultMatrix.reset();
290 fDefaultMatrixInv.reset();
291
292 if (fWindow->supportsContentRect() && fWindow->scaleContentToFit()) {
293 const SkRect contentRect = fWindow->getContentRect();
294 const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
295 const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
296 if (contentRect.width() > 0 && contentRect.height() > 0) {
297 fDefaultMatrix.setRectToRect(slideBounds, contentRect, SkMatrix::kStart_ScaleToFit);
liyuqianbeb1c672016-05-20 11:41:01 -0700298 SkAssertResult(fDefaultMatrix.invert(&fDefaultMatrixInv));
liyuqiane46e4f02016-05-20 07:32:19 -0700299 }
300 }
301
302 if (fWindow->supportsContentRect()) {
303 const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
304 SkRect windowRect = fWindow->getContentRect();
305 fDefaultMatrixInv.mapRect(&windowRect);
jvanverth1e305ba2016-06-01 09:39:15 -0700306 fGesture.setTransLimit(SkRect::MakeWH(SkIntToScalar(slideSize.width()),
307 SkIntToScalar(slideSize.height())),
308 windowRect);
liyuqiane46e4f02016-05-20 07:32:19 -0700309 }
310
brianosman05de2162016-05-06 13:28:57 -0700311 this->updateTitle();
liyuqiane5a6cd92016-05-27 08:52:52 -0700312 this->updateUIState();
jvanverthc265a922016-04-08 12:51:45 -0700313 if (previousSlide >= 0) {
314 fSlides[previousSlide]->unload();
315 }
jvanverthc265a922016-04-08 12:51:45 -0700316 fWindow->inval();
317}
318
319#define MAX_ZOOM_LEVEL 8
320#define MIN_ZOOM_LEVEL -8
321
jvanverth34524262016-05-04 13:49:13 -0700322void Viewer::changeZoomLevel(float delta) {
jvanverthc265a922016-04-08 12:51:45 -0700323 fZoomLevel += delta;
324 if (fZoomLevel > 0) {
325 fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
326 fZoomScale = fZoomLevel + SK_Scalar1;
327 } else if (fZoomLevel < 0) {
328 fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
329 fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
330 } else {
331 fZoomScale = SK_Scalar1;
332 }
jvanverthc265a922016-04-08 12:51:45 -0700333}
334
liyuqiand3cdbca2016-05-17 12:44:20 -0700335SkMatrix Viewer::computeMatrix() {
jvanverthc265a922016-04-08 12:51:45 -0700336 SkMatrix m;
337 m.reset();
338
339 if (fZoomLevel) {
340 SkPoint center;
341 //m = this->getLocalMatrix();//.invert(&m);
342 m.mapXY(fZoomCenterX, fZoomCenterY, &center);
343 SkScalar cx = center.fX;
344 SkScalar cy = center.fY;
345
346 m.setTranslate(-cx, -cy);
347 m.postScale(fZoomScale, fZoomScale);
348 m.postTranslate(cx, cy);
349 }
350
liyuqiand3cdbca2016-05-17 12:44:20 -0700351 m.preConcat(fGesture.localM());
352 m.preConcat(fGesture.globalM());
jvanverthc265a922016-04-08 12:51:45 -0700353
liyuqiand3cdbca2016-05-17 12:44:20 -0700354 return m;
jvanverthc265a922016-04-08 12:51:45 -0700355}
356
liyuqian6f163d22016-06-13 12:26:45 -0700357void Viewer::drawSlide(SkCanvas* canvas, bool inSplitScreen) {
358 SkASSERT(!inSplitScreen || fWindow->supportsContentRect());
359
jvanverthc265a922016-04-08 12:51:45 -0700360 int count = canvas->save();
djsollen12d62a72016-04-21 07:59:44 -0700361
362 if (fWindow->supportsContentRect()) {
363 SkRect contentRect = fWindow->getContentRect();
liyuqian6f163d22016-06-13 12:26:45 -0700364 // If inSplitScreen, translate the image half screen to the right.
365 // Thus we have two copies of the image on each half of the screen.
liyuqian401cf482016-06-13 14:38:35 -0700366 contentRect.fLeft +=
367 inSplitScreen ? (contentRect.fRight - contentRect.fLeft) * 0.5f : 0.0f;
djsollen12d62a72016-04-21 07:59:44 -0700368 canvas->clipRect(contentRect);
369 canvas->translate(contentRect.fLeft, contentRect.fTop);
370 }
371
372 canvas->clear(SK_ColorWHITE);
liyuqiane46e4f02016-05-20 07:32:19 -0700373 canvas->concat(fDefaultMatrix);
liyuqiand3cdbca2016-05-17 12:44:20 -0700374 canvas->concat(computeMatrix());
jvanverth3d6ed3a2016-04-07 11:09:51 -0700375
liyuqian74959a12016-06-16 14:10:34 -0700376 if (inSplitScreen) {
377 sk_sp<SkSurface> offscreenSurface = fWindow->getOffscreenSurface(true);
liyuqianed330c82016-06-16 18:09:11 -0700378 offscreenSurface->getCanvas()->getMetaData().setBool(kImageColorXformMetaData, true);
liyuqian74959a12016-06-16 14:10:34 -0700379 fSlides[fCurrentSlide]->draw(offscreenSurface->getCanvas());
380 sk_sp<SkImage> snapshot = offscreenSurface->makeImageSnapshot();
381 canvas->drawImage(snapshot, 0, 0);
382 } else {
383 fSlides[fCurrentSlide]->draw(canvas);
384 }
385
jvanverthc265a922016-04-08 12:51:45 -0700386 canvas->restoreToCount(count);
liyuqian74959a12016-06-16 14:10:34 -0700387
388 if (inSplitScreen) {
389 // Draw split line
390 SkPaint paint;
391 SkScalar intervals[] = {10.0f, 5.0f};
392 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0.0f));
393 SkRect contentRect = fWindow->getContentRect();
394 SkScalar middleX = (contentRect.fLeft + contentRect.fRight) * 0.5f;
395 canvas->drawLine(middleX, contentRect.fTop, middleX, contentRect.fBottom, paint);
396 }
liyuqian6f163d22016-06-13 12:26:45 -0700397}
398
399void Viewer::onPaint(SkCanvas* canvas) {
400 drawSlide(canvas, false);
401 if (fSplitScreen && fWindow->supportsContentRect()) {
402 drawSlide(canvas, true);
403 }
jvanverthc265a922016-04-08 12:51:45 -0700404
405 if (fDisplayStats) {
406 drawStats(canvas);
407 }
brianosman622c8d52016-05-10 06:50:49 -0700408 fCommands.drawHelp(canvas);
jvanverth3d6ed3a2016-04-07 11:09:51 -0700409}
410
jvanverth814e38d2016-06-06 08:48:47 -0700411bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y) {
liyuqiand3cdbca2016-05-17 12:44:20 -0700412 void* castedOwner = reinterpret_cast<void*>(owner);
liyuqiane46e4f02016-05-20 07:32:19 -0700413 SkPoint touchPoint = fDefaultMatrixInv.mapXY(x, y);
liyuqiand3cdbca2016-05-17 12:44:20 -0700414 switch (state) {
415 case Window::kUp_InputState: {
416 fGesture.touchEnd(castedOwner);
417 break;
418 }
419 case Window::kDown_InputState: {
liyuqiane46e4f02016-05-20 07:32:19 -0700420 fGesture.touchBegin(castedOwner, touchPoint.fX, touchPoint.fY);
liyuqiand3cdbca2016-05-17 12:44:20 -0700421 break;
422 }
423 case Window::kMove_InputState: {
liyuqiane46e4f02016-05-20 07:32:19 -0700424 fGesture.touchMoved(castedOwner, touchPoint.fX, touchPoint.fY);
liyuqiand3cdbca2016-05-17 12:44:20 -0700425 break;
426 }
427 }
428 fWindow->inval();
429 return true;
430}
431
jvanverth34524262016-05-04 13:49:13 -0700432void Viewer::drawStats(SkCanvas* canvas) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700433 static const float kPixelPerMS = 2.0f;
434 static const int kDisplayWidth = 130;
435 static const int kDisplayHeight = 100;
436 static const int kDisplayPadding = 10;
437 static const int kGraphPadding = 3;
438 static const SkScalar kBaseMS = 1000.f / 60.f; // ms/frame to hit 60 fps
439
440 SkISize canvasSize = canvas->getDeviceSize();
441 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding),
442 SkIntToScalar(kDisplayPadding),
443 SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight));
444 SkPaint paint;
445 canvas->save();
446
djsollen12d62a72016-04-21 07:59:44 -0700447 if (fWindow->supportsContentRect()) {
448 SkRect contentRect = fWindow->getContentRect();
449 canvas->clipRect(contentRect);
450 canvas->translate(contentRect.fLeft, contentRect.fTop);
451 }
452
jvanverth3d6ed3a2016-04-07 11:09:51 -0700453 canvas->clipRect(rect);
454 paint.setColor(SK_ColorBLACK);
455 canvas->drawRect(rect, paint);
456 // draw the 16ms line
457 paint.setColor(SK_ColorLTGRAY);
458 canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS,
459 rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint);
460 paint.setColor(SK_ColorRED);
461 paint.setStyle(SkPaint::kStroke_Style);
462 canvas->drawRect(rect, paint);
463
464 int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding;
465 const int xStep = 2;
466 const int startY = SkScalarTruncToInt(rect.fBottom);
467 int i = fCurrentMeasurement;
468 do {
469 int endY = startY - (int)(fMeasurements[i] * kPixelPerMS + 0.5); // round to nearest value
470 canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
471 SkIntToScalar(x), SkIntToScalar(endY), paint);
472 i++;
473 i &= (kMeasurementCount - 1); // fast mod
474 x += xStep;
475 } while (i != fCurrentMeasurement);
jvanverth9f372462016-04-06 06:08:59 -0700476
477 canvas->restore();
478}
479
jvanverth34524262016-05-04 13:49:13 -0700480void Viewer::onIdle(double ms) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700481 // Record measurements
482 fMeasurements[fCurrentMeasurement++] = ms;
483 fCurrentMeasurement &= (kMeasurementCount - 1); // fast mod
484 SkASSERT(fCurrentMeasurement < kMeasurementCount);
485
jvanverthc265a922016-04-08 12:51:45 -0700486 fAnimTimer.updateTime();
jvanverth9d5e47f2016-04-26 08:01:33 -0700487 if (fSlides[fCurrentSlide]->animate(fAnimTimer) || fDisplayStats) {
jvanverthc265a922016-04-08 12:51:45 -0700488 fWindow->inval();
liyuqian1f508fd2016-06-07 06:57:40 -0700489 updateUIState(); // Update the FPS
jvanverthc265a922016-04-08 12:51:45 -0700490 }
jvanverth9f372462016-04-06 06:08:59 -0700491}
liyuqiane5a6cd92016-05-27 08:52:52 -0700492
493void Viewer::updateUIState() {
liyuqianb73c24b2016-06-03 08:47:23 -0700494 // Slide state
liyuqiane5a6cd92016-05-27 08:52:52 -0700495 Json::Value slideState(Json::objectValue);
496 slideState[kName] = kSlideStateName;
497 slideState[kValue] = fSlides[fCurrentSlide]->getName().c_str();
liyuqian1f508fd2016-06-07 06:57:40 -0700498 if (fAllSlideNames.size() == 0) {
499 for(auto slide : fSlides) {
500 fAllSlideNames.append(Json::Value(slide->getName().c_str()));
501 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700502 }
liyuqian1f508fd2016-06-07 06:57:40 -0700503 slideState[kOptions] = fAllSlideNames;
liyuqiane5a6cd92016-05-27 08:52:52 -0700504
liyuqianb73c24b2016-06-03 08:47:23 -0700505 // Backend state
liyuqiane5a6cd92016-05-27 08:52:52 -0700506 Json::Value backendState(Json::objectValue);
507 backendState[kName] = kBackendStateName;
liyuqian6cb70252016-06-02 12:16:25 -0700508 backendState[kValue] = kBackendTypeStrings[fBackendType];
liyuqiane5a6cd92016-05-27 08:52:52 -0700509 backendState[kOptions] = Json::Value(Json::arrayValue);
liyuqianb73c24b2016-06-03 08:47:23 -0700510 for (auto str : kBackendTypeStrings) {
liyuqian6cb70252016-06-02 12:16:25 -0700511 backendState[kOptions].append(Json::Value(str));
512 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700513
liyuqianb73c24b2016-06-03 08:47:23 -0700514 // Softkey state
515 Json::Value softkeyState(Json::objectValue);
516 softkeyState[kName] = kSoftkeyStateName;
517 softkeyState[kValue] = kSoftkeyHint;
518 softkeyState[kOptions] = Json::Value(Json::arrayValue);
519 softkeyState[kOptions].append(kSoftkeyHint);
520 for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) {
521 softkeyState[kOptions].append(Json::Value(softkey.c_str()));
522 }
523
liyuqian1f508fd2016-06-07 06:57:40 -0700524 // FPS state
525 Json::Value fpsState(Json::objectValue);
526 fpsState[kName] = kFpsStateName;
527 double measurement = fMeasurements[
528 (fCurrentMeasurement + (kMeasurementCount-1)) % kMeasurementCount
529 ];
530 fpsState[kValue] = SkStringPrintf("%8.3lf ms", measurement).c_str();
531 fpsState[kOptions] = Json::Value(Json::arrayValue);
532
liyuqian6f163d22016-06-13 12:26:45 -0700533 // Split screen state
534 Json::Value splitScreenState(Json::objectValue);
535 splitScreenState[kName] = kSplitScreenStateName;
536 splitScreenState[kValue] = fSplitScreen ? kON : kOFF;
537 splitScreenState[kOptions] = Json::Value(Json::arrayValue);
538 splitScreenState[kOptions].append(kON);
539 splitScreenState[kOptions].append(kOFF);
540
liyuqiane5a6cd92016-05-27 08:52:52 -0700541 Json::Value state(Json::arrayValue);
542 state.append(slideState);
543 state.append(backendState);
liyuqianb73c24b2016-06-03 08:47:23 -0700544 state.append(softkeyState);
liyuqian1f508fd2016-06-07 06:57:40 -0700545 state.append(fpsState);
liyuqian6f163d22016-06-13 12:26:45 -0700546 state.append(splitScreenState);
liyuqiane5a6cd92016-05-27 08:52:52 -0700547
548 fWindow->setUIState(state);
549}
550
551void Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateValue) {
liyuqian6cb70252016-06-02 12:16:25 -0700552 // For those who will add more features to handle the state change in this function:
553 // After the change, please call updateUIState no notify the frontend (e.g., Android app).
554 // For example, after slide change, updateUIState is called inside setupCurrentSlide;
555 // after backend change, updateUIState is called in this function.
liyuqiane5a6cd92016-05-27 08:52:52 -0700556 if (stateName.equals(kSlideStateName)) {
557 int previousSlide = fCurrentSlide;
558 fCurrentSlide = 0;
559 for(auto slide : fSlides) {
560 if (slide->getName().equals(stateValue)) {
561 setupCurrentSlide(previousSlide);
562 break;
563 }
564 fCurrentSlide++;
565 }
566 if (fCurrentSlide >= fSlides.count()) {
567 fCurrentSlide = previousSlide;
568 SkDebugf("Slide not found: %s", stateValue.c_str());
569 }
liyuqian6cb70252016-06-02 12:16:25 -0700570 } else if (stateName.equals(kBackendStateName)) {
571 for (int i = 0; i < sk_app::Window::kBackendTypeCount; i++) {
572 if (stateValue.equals(kBackendTypeStrings[i])) {
573 if (fBackendType != i) {
574 fBackendType = (sk_app::Window::BackendType)i;
575 fWindow->detach();
576 fWindow->attach(fBackendType, DisplayParams());
577 fWindow->inval();
578 updateTitle();
579 updateUIState();
580 }
581 break;
582 }
583 }
liyuqianb73c24b2016-06-03 08:47:23 -0700584 } else if (stateName.equals(kSoftkeyStateName)) {
585 if (!stateValue.equals(kSoftkeyHint)) {
586 fCommands.onSoftkey(stateValue);
587 updateUIState(); // This is still needed to reset the value to kSoftkeyHint
588 }
liyuqian6f163d22016-06-13 12:26:45 -0700589 } else if (stateName.equals(kSplitScreenStateName)) {
590 bool newSplitScreen = stateValue.equals(kON);
591 if (newSplitScreen != fSplitScreen) {
592 fSplitScreen = newSplitScreen;
593 fWindow->inval();
594 updateUIState();
595 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700596 } else {
597 SkDebugf("Unknown stateName: %s", stateName.c_str());
598 }
599}