blob: 7015dad458f1ebfcb3e6daa9d36e33e4ccff24e8 [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"
11#include "SKPSlide.h"
jvanverth9f372462016-04-06 06:08:59 -070012
jvanverth2bb3b6d2016-04-08 07:24:09 -070013#include "SkCanvas.h"
14#include "SkCommonFlags.h"
15#include "SkOSFile.h"
16#include "SkRandom.h"
17#include "SkStream.h"
jvanverth9f372462016-04-06 06:08:59 -070018
jvanverth34524262016-05-04 13:49:13 -070019using namespace sk_app;
20
jvanverth9f372462016-04-06 06:08:59 -070021Application* Application::Create(int argc, char** argv, void* platformData) {
jvanverth34524262016-05-04 13:49:13 -070022 return new Viewer(argc, argv, platformData);
jvanverth9f372462016-04-06 06:08:59 -070023}
24
jvanverth9f372462016-04-06 06:08:59 -070025static void on_paint_handler(SkCanvas* canvas, void* userData) {
jvanverth34524262016-05-04 13:49:13 -070026 Viewer* vv = reinterpret_cast<Viewer*>(userData);
jvanverth9f372462016-04-06 06:08:59 -070027
28 return vv->onPaint(canvas);
29}
30
jvanverth814e38d2016-06-06 08:48:47 -070031static bool on_touch_handler(intptr_t owner, Window::InputState state, float x, float y, void* userData)
liyuqiand3cdbca2016-05-17 12:44:20 -070032{
33 Viewer* viewer = reinterpret_cast<Viewer*>(userData);
34
35 return viewer->onTouch(owner, state, x, y);
36}
37
liyuqiane5a6cd92016-05-27 08:52:52 -070038static void on_ui_state_changed_handler(const SkString& stateName, const SkString& stateValue, void* userData) {
39 Viewer* viewer = reinterpret_cast<Viewer*>(userData);
40
41 return viewer->onUIStateChanged(stateName, stateValue);
42}
43
44DEFINE_bool2(fullscreen, f, true, "Run fullscreen.");
jvanverth2bb3b6d2016-04-08 07:24:09 -070045DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder.");
46DEFINE_string2(match, m, nullptr,
47 "[~][^]substring[$] [...] of bench name to run.\n"
48 "Multiple matches may be separated by spaces.\n"
49 "~ causes a matching bench to always be skipped\n"
50 "^ requires the start of the bench to match\n"
51 "$ requires the end of the bench to match\n"
52 "^ and $ requires an exact match\n"
53 "If a bench does not match any list entry,\n"
54 "it is skipped unless some list entry starts with ~");
55DEFINE_string(skps, "skps", "Directory to read skps from.");
jvanverth85f758c2016-05-27 06:47:08 -070056DEFINE_bool(vulkan, true, "Run with Vulkan.");
jvanverth2bb3b6d2016-04-08 07:24:09 -070057
jvanverthaf236b52016-05-20 06:01:06 -070058const char *kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
59 " [OpenGL]",
liyuqiand94ad582016-06-07 14:22:37 -070060 " [Vulkan]",
61 " [Raster]"
jvanverthaf236b52016-05-20 06:01:06 -070062};
63
liyuqiane5a6cd92016-05-27 08:52:52 -070064const char* kName = "name";
65const char* kValue = "value";
66const char* kOptions = "options";
67const char* kSlideStateName = "Slide";
68const char* kBackendStateName = "Backend";
liyuqianb73c24b2016-06-03 08:47:23 -070069const char* kSoftkeyStateName = "Softkey";
70const char* kSoftkeyHint = "Please select a softkey";
liyuqian1f508fd2016-06-07 06:57:40 -070071const char* kFpsStateName = "FPS";
liyuqiane5a6cd92016-05-27 08:52:52 -070072
jvanverth34524262016-05-04 13:49:13 -070073Viewer::Viewer(int argc, char** argv, void* platformData)
jvanverthc265a922016-04-08 12:51:45 -070074 : fCurrentMeasurement(0)
75 , fDisplayStats(false)
jvanverthaf236b52016-05-20 06:01:06 -070076 , fBackendType(sk_app::Window::kVulkan_BackendType)
egdaniel2a0bb0a2016-04-11 08:30:40 -070077 , fZoomCenterX(0.0f)
78 , fZoomCenterY(0.0f)
79 , fZoomLevel(0.0f)
80 , fZoomScale(SK_Scalar1)
jvanverthc265a922016-04-08 12:51:45 -070081{
jvanverth3d6ed3a2016-04-07 11:09:51 -070082 memset(fMeasurements, 0, sizeof(fMeasurements));
jvanverth9f372462016-04-06 06:08:59 -070083
jvanverth2bb3b6d2016-04-08 07:24:09 -070084 SkDebugf("Command line arguments: ");
85 for (int i = 1; i < argc; ++i) {
86 SkDebugf("%s ", argv[i]);
87 }
88 SkDebugf("\n");
89
90 SkCommandLineFlags::Parse(argc, argv);
91
jvanverth85f758c2016-05-27 06:47:08 -070092 fBackendType = FLAGS_vulkan ? sk_app::Window::kVulkan_BackendType
93 : sk_app::Window::kNativeGL_BackendType;
94
jvanverth9f372462016-04-06 06:08:59 -070095 fWindow = Window::CreateNativeWindow(platformData);
jvanverthaf236b52016-05-20 06:01:06 -070096 fWindow->attach(fBackendType, DisplayParams());
jvanverth9f372462016-04-06 06:08:59 -070097
98 // register callbacks
brianosman622c8d52016-05-10 06:50:49 -070099 fCommands.attach(fWindow);
jvanverth9f372462016-04-06 06:08:59 -0700100 fWindow->registerPaintFunc(on_paint_handler, this);
liyuqiand3cdbca2016-05-17 12:44:20 -0700101 fWindow->registerTouchFunc(on_touch_handler, this);
liyuqiane5a6cd92016-05-27 08:52:52 -0700102 fWindow->registerUIStateChangedFunc(on_ui_state_changed_handler, this);
jvanverth9f372462016-04-06 06:08:59 -0700103
brianosman622c8d52016-05-10 06:50:49 -0700104 // add key-bindings
105 fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() {
106 this->fDisplayStats = !this->fDisplayStats;
107 fWindow->inval();
108 });
109 fCommands.addCommand('c', "Modes", "Toggle sRGB color mode", [this]() {
110 DisplayParams params = fWindow->getDisplayParams();
111 params.fProfileType = (kLinear_SkColorProfileType == params.fProfileType)
112 ? kSRGB_SkColorProfileType : kLinear_SkColorProfileType;
113 fWindow->setDisplayParams(params);
114 this->updateTitle();
115 fWindow->inval();
116 });
117 fCommands.addCommand(Window::Key::kRight, "Right", "Navigation", "Next slide", [this]() {
118 int previousSlide = fCurrentSlide;
119 fCurrentSlide++;
120 if (fCurrentSlide >= fSlides.count()) {
121 fCurrentSlide = 0;
122 }
123 this->setupCurrentSlide(previousSlide);
124 });
125 fCommands.addCommand(Window::Key::kLeft, "Left", "Navigation", "Previous slide", [this]() {
126 int previousSlide = fCurrentSlide;
127 fCurrentSlide--;
128 if (fCurrentSlide < 0) {
129 fCurrentSlide = fSlides.count() - 1;
130 }
131 this->setupCurrentSlide(previousSlide);
132 });
133 fCommands.addCommand(Window::Key::kUp, "Up", "Transform", "Zoom in", [this]() {
134 this->changeZoomLevel(1.f / 32.f);
135 fWindow->inval();
136 });
137 fCommands.addCommand(Window::Key::kDown, "Down", "Transform", "Zoom out", [this]() {
138 this->changeZoomLevel(-1.f / 32.f);
139 fWindow->inval();
140 });
jvanverth85f758c2016-05-27 06:47:08 -0700141#if 0 // this doesn't seem to work on any platform right now
jvanverthaf236b52016-05-20 06:01:06 -0700142#ifndef SK_BUILD_FOR_ANDROID
143 fCommands.addCommand('d', "Modes", "Change rendering backend", [this]() {
144 fWindow->detach();
145
146 if (sk_app::Window::kVulkan_BackendType == fBackendType) {
147 fBackendType = sk_app::Window::kNativeGL_BackendType;
148 }
jvanverth85f758c2016-05-27 06:47:08 -0700149 // TODO: get Vulkan -> OpenGL working on Windows without swapchain creation failure
jvanverthaf236b52016-05-20 06:01:06 -0700150 //else if (sk_app::Window::kNativeGL_BackendType == fBackendType) {
151 // fBackendType = sk_app::Window::kVulkan_BackendType;
152 //}
153
154 fWindow->attach(fBackendType, DisplayParams());
155 this->updateTitle();
jvanverth85f758c2016-05-27 06:47:08 -0700156 fWindow->inval();
jvanverthaf236b52016-05-20 06:01:06 -0700157 });
158#endif
jvanverth85f758c2016-05-27 06:47:08 -0700159#endif
brianosman622c8d52016-05-10 06:50:49 -0700160
jvanverth2bb3b6d2016-04-08 07:24:09 -0700161 // set up slides
162 this->initSlides();
163
djsollen12d62a72016-04-21 07:59:44 -0700164 fAnimTimer.run();
165
jvanverth2bb3b6d2016-04-08 07:24:09 -0700166 // set up first frame
jvanverth2bb3b6d2016-04-08 07:24:09 -0700167 fCurrentSlide = 0;
jvanverthc265a922016-04-08 12:51:45 -0700168 setupCurrentSlide(-1);
jvanverthc265a922016-04-08 12:51:45 -0700169
jvanverth9f372462016-04-06 06:08:59 -0700170 fWindow->show();
171}
172
jvanverth34524262016-05-04 13:49:13 -0700173void Viewer::initSlides() {
liyuqian1f508fd2016-06-07 06:57:40 -0700174 fAllSlideNames = Json::Value(Json::arrayValue);
175
jvanverth2bb3b6d2016-04-08 07:24:09 -0700176 const skiagm::GMRegistry* gms(skiagm::GMRegistry::Head());
177 while (gms) {
178 SkAutoTDelete<skiagm::GM> gm(gms->factory()(nullptr));
179
180 if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, gm->getName())) {
181 sk_sp<Slide> slide(new GMSlide(gm.release()));
182 fSlides.push_back(slide);
183 }
184
185 gms = gms->next();
186 }
187
188 // reverse array
189 for (int i = 0; i < fSlides.count()/2; ++i) {
190 sk_sp<Slide> temp = fSlides[i];
191 fSlides[i] = fSlides[fSlides.count() - i - 1];
192 fSlides[fSlides.count() - i - 1] = temp;
193 }
194
195 // SKPs
196 for (int i = 0; i < FLAGS_skps.count(); i++) {
197 if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
jvanverthc265a922016-04-08 12:51:45 -0700198 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, FLAGS_skps[i])) {
199 continue;
200 }
201
jvanverth2bb3b6d2016-04-08 07:24:09 -0700202 SkString path(FLAGS_skps[i]);
jvanverthc265a922016-04-08 12:51:45 -0700203 sk_sp<SKPSlide> slide(new SKPSlide(SkOSPath::Basename(path.c_str()), path));
jvanverth2bb3b6d2016-04-08 07:24:09 -0700204 if (slide) {
205 fSlides.push_back(slide);
206 }
207 } else {
208 SkOSFile::Iter it(FLAGS_skps[i], ".skp");
jvanverthc265a922016-04-08 12:51:45 -0700209 SkString skpName;
210 while (it.next(&skpName)) {
211 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, skpName.c_str())) {
212 continue;
213 }
214
215 SkString path = SkOSPath::Join(FLAGS_skps[i], skpName.c_str());
216 sk_sp<SKPSlide> slide(new SKPSlide(skpName, path));
jvanverth2bb3b6d2016-04-08 07:24:09 -0700217 if (slide) {
218 fSlides.push_back(slide);
219 }
220 }
221 }
222 }
223}
224
225
jvanverth34524262016-05-04 13:49:13 -0700226Viewer::~Viewer() {
jvanverth9f372462016-04-06 06:08:59 -0700227 fWindow->detach();
228 delete fWindow;
229}
230
brianosman05de2162016-05-06 13:28:57 -0700231void Viewer::updateTitle() {
jvanverth34524262016-05-04 13:49:13 -0700232 SkString title("Viewer: ");
jvanverthc265a922016-04-08 12:51:45 -0700233 title.append(fSlides[fCurrentSlide]->getName());
brianosman05de2162016-05-06 13:28:57 -0700234 if (kSRGB_SkColorProfileType == fWindow->getDisplayParams().fProfileType) {
235 title.append(" sRGB");
236 }
jvanverthaf236b52016-05-20 06:01:06 -0700237 title.append(kBackendTypeStrings[fBackendType]);
brianosman05de2162016-05-06 13:28:57 -0700238 fWindow->setTitle(title.c_str());
239}
240
241void Viewer::setupCurrentSlide(int previousSlide) {
liyuqiane5a6cd92016-05-27 08:52:52 -0700242 if (fCurrentSlide == previousSlide) {
243 return; // no change; do nothing
244 }
245
liyuqiane46e4f02016-05-20 07:32:19 -0700246 fGesture.reset();
247 fDefaultMatrix.reset();
248 fDefaultMatrixInv.reset();
249
250 if (fWindow->supportsContentRect() && fWindow->scaleContentToFit()) {
251 const SkRect contentRect = fWindow->getContentRect();
252 const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
253 const SkRect slideBounds = SkRect::MakeIWH(slideSize.width(), slideSize.height());
254 if (contentRect.width() > 0 && contentRect.height() > 0) {
255 fDefaultMatrix.setRectToRect(slideBounds, contentRect, SkMatrix::kStart_ScaleToFit);
liyuqianbeb1c672016-05-20 11:41:01 -0700256 SkAssertResult(fDefaultMatrix.invert(&fDefaultMatrixInv));
liyuqiane46e4f02016-05-20 07:32:19 -0700257 }
258 }
259
260 if (fWindow->supportsContentRect()) {
261 const SkISize slideSize = fSlides[fCurrentSlide]->getDimensions();
262 SkRect windowRect = fWindow->getContentRect();
263 fDefaultMatrixInv.mapRect(&windowRect);
jvanverth1e305ba2016-06-01 09:39:15 -0700264 fGesture.setTransLimit(SkRect::MakeWH(SkIntToScalar(slideSize.width()),
265 SkIntToScalar(slideSize.height())),
266 windowRect);
liyuqiane46e4f02016-05-20 07:32:19 -0700267 }
268
brianosman05de2162016-05-06 13:28:57 -0700269 this->updateTitle();
liyuqiane5a6cd92016-05-27 08:52:52 -0700270 this->updateUIState();
jvanverthc265a922016-04-08 12:51:45 -0700271 fSlides[fCurrentSlide]->load();
272 if (previousSlide >= 0) {
273 fSlides[previousSlide]->unload();
274 }
jvanverthc265a922016-04-08 12:51:45 -0700275 fWindow->inval();
276}
277
278#define MAX_ZOOM_LEVEL 8
279#define MIN_ZOOM_LEVEL -8
280
jvanverth34524262016-05-04 13:49:13 -0700281void Viewer::changeZoomLevel(float delta) {
jvanverthc265a922016-04-08 12:51:45 -0700282 fZoomLevel += delta;
283 if (fZoomLevel > 0) {
284 fZoomLevel = SkMinScalar(fZoomLevel, MAX_ZOOM_LEVEL);
285 fZoomScale = fZoomLevel + SK_Scalar1;
286 } else if (fZoomLevel < 0) {
287 fZoomLevel = SkMaxScalar(fZoomLevel, MIN_ZOOM_LEVEL);
288 fZoomScale = SK_Scalar1 / (SK_Scalar1 - fZoomLevel);
289 } else {
290 fZoomScale = SK_Scalar1;
291 }
jvanverthc265a922016-04-08 12:51:45 -0700292}
293
liyuqiand3cdbca2016-05-17 12:44:20 -0700294SkMatrix Viewer::computeMatrix() {
jvanverthc265a922016-04-08 12:51:45 -0700295 SkMatrix m;
296 m.reset();
297
298 if (fZoomLevel) {
299 SkPoint center;
300 //m = this->getLocalMatrix();//.invert(&m);
301 m.mapXY(fZoomCenterX, fZoomCenterY, &center);
302 SkScalar cx = center.fX;
303 SkScalar cy = center.fY;
304
305 m.setTranslate(-cx, -cy);
306 m.postScale(fZoomScale, fZoomScale);
307 m.postTranslate(cx, cy);
308 }
309
liyuqiand3cdbca2016-05-17 12:44:20 -0700310 m.preConcat(fGesture.localM());
311 m.preConcat(fGesture.globalM());
jvanverthc265a922016-04-08 12:51:45 -0700312
liyuqiand3cdbca2016-05-17 12:44:20 -0700313 return m;
jvanverthc265a922016-04-08 12:51:45 -0700314}
315
jvanverth34524262016-05-04 13:49:13 -0700316void Viewer::onPaint(SkCanvas* canvas) {
jvanverthc265a922016-04-08 12:51:45 -0700317 int count = canvas->save();
djsollen12d62a72016-04-21 07:59:44 -0700318
319 if (fWindow->supportsContentRect()) {
320 SkRect contentRect = fWindow->getContentRect();
321 canvas->clipRect(contentRect);
322 canvas->translate(contentRect.fLeft, contentRect.fTop);
323 }
324
325 canvas->clear(SK_ColorWHITE);
liyuqiane46e4f02016-05-20 07:32:19 -0700326 canvas->concat(fDefaultMatrix);
liyuqiand3cdbca2016-05-17 12:44:20 -0700327 canvas->concat(computeMatrix());
jvanverth3d6ed3a2016-04-07 11:09:51 -0700328
jvanverthc265a922016-04-08 12:51:45 -0700329 fSlides[fCurrentSlide]->draw(canvas);
330 canvas->restoreToCount(count);
331
332 if (fDisplayStats) {
333 drawStats(canvas);
334 }
brianosman622c8d52016-05-10 06:50:49 -0700335 fCommands.drawHelp(canvas);
jvanverth3d6ed3a2016-04-07 11:09:51 -0700336}
337
jvanverth814e38d2016-06-06 08:48:47 -0700338bool Viewer::onTouch(intptr_t owner, Window::InputState state, float x, float y) {
liyuqiand3cdbca2016-05-17 12:44:20 -0700339 void* castedOwner = reinterpret_cast<void*>(owner);
liyuqiane46e4f02016-05-20 07:32:19 -0700340 SkPoint touchPoint = fDefaultMatrixInv.mapXY(x, y);
liyuqiand3cdbca2016-05-17 12:44:20 -0700341 switch (state) {
342 case Window::kUp_InputState: {
343 fGesture.touchEnd(castedOwner);
344 break;
345 }
346 case Window::kDown_InputState: {
liyuqiane46e4f02016-05-20 07:32:19 -0700347 fGesture.touchBegin(castedOwner, touchPoint.fX, touchPoint.fY);
liyuqiand3cdbca2016-05-17 12:44:20 -0700348 break;
349 }
350 case Window::kMove_InputState: {
liyuqiane46e4f02016-05-20 07:32:19 -0700351 fGesture.touchMoved(castedOwner, touchPoint.fX, touchPoint.fY);
liyuqiand3cdbca2016-05-17 12:44:20 -0700352 break;
353 }
354 }
355 fWindow->inval();
356 return true;
357}
358
jvanverth34524262016-05-04 13:49:13 -0700359void Viewer::drawStats(SkCanvas* canvas) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700360 static const float kPixelPerMS = 2.0f;
361 static const int kDisplayWidth = 130;
362 static const int kDisplayHeight = 100;
363 static const int kDisplayPadding = 10;
364 static const int kGraphPadding = 3;
365 static const SkScalar kBaseMS = 1000.f / 60.f; // ms/frame to hit 60 fps
366
367 SkISize canvasSize = canvas->getDeviceSize();
368 SkRect rect = SkRect::MakeXYWH(SkIntToScalar(canvasSize.fWidth-kDisplayWidth-kDisplayPadding),
369 SkIntToScalar(kDisplayPadding),
370 SkIntToScalar(kDisplayWidth), SkIntToScalar(kDisplayHeight));
371 SkPaint paint;
372 canvas->save();
373
djsollen12d62a72016-04-21 07:59:44 -0700374 if (fWindow->supportsContentRect()) {
375 SkRect contentRect = fWindow->getContentRect();
376 canvas->clipRect(contentRect);
377 canvas->translate(contentRect.fLeft, contentRect.fTop);
378 }
379
jvanverth3d6ed3a2016-04-07 11:09:51 -0700380 canvas->clipRect(rect);
381 paint.setColor(SK_ColorBLACK);
382 canvas->drawRect(rect, paint);
383 // draw the 16ms line
384 paint.setColor(SK_ColorLTGRAY);
385 canvas->drawLine(rect.fLeft, rect.fBottom - kBaseMS*kPixelPerMS,
386 rect.fRight, rect.fBottom - kBaseMS*kPixelPerMS, paint);
387 paint.setColor(SK_ColorRED);
388 paint.setStyle(SkPaint::kStroke_Style);
389 canvas->drawRect(rect, paint);
390
391 int x = SkScalarTruncToInt(rect.fLeft) + kGraphPadding;
392 const int xStep = 2;
393 const int startY = SkScalarTruncToInt(rect.fBottom);
394 int i = fCurrentMeasurement;
395 do {
396 int endY = startY - (int)(fMeasurements[i] * kPixelPerMS + 0.5); // round to nearest value
397 canvas->drawLine(SkIntToScalar(x), SkIntToScalar(startY),
398 SkIntToScalar(x), SkIntToScalar(endY), paint);
399 i++;
400 i &= (kMeasurementCount - 1); // fast mod
401 x += xStep;
402 } while (i != fCurrentMeasurement);
jvanverth9f372462016-04-06 06:08:59 -0700403
404 canvas->restore();
405}
406
jvanverth34524262016-05-04 13:49:13 -0700407void Viewer::onIdle(double ms) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700408 // Record measurements
409 fMeasurements[fCurrentMeasurement++] = ms;
410 fCurrentMeasurement &= (kMeasurementCount - 1); // fast mod
411 SkASSERT(fCurrentMeasurement < kMeasurementCount);
412
jvanverthc265a922016-04-08 12:51:45 -0700413 fAnimTimer.updateTime();
jvanverth9d5e47f2016-04-26 08:01:33 -0700414 if (fSlides[fCurrentSlide]->animate(fAnimTimer) || fDisplayStats) {
jvanverthc265a922016-04-08 12:51:45 -0700415 fWindow->inval();
liyuqian1f508fd2016-06-07 06:57:40 -0700416 updateUIState(); // Update the FPS
jvanverthc265a922016-04-08 12:51:45 -0700417 }
jvanverth9f372462016-04-06 06:08:59 -0700418}
liyuqiane5a6cd92016-05-27 08:52:52 -0700419
420void Viewer::updateUIState() {
liyuqianb73c24b2016-06-03 08:47:23 -0700421 // Slide state
liyuqiane5a6cd92016-05-27 08:52:52 -0700422 Json::Value slideState(Json::objectValue);
423 slideState[kName] = kSlideStateName;
424 slideState[kValue] = fSlides[fCurrentSlide]->getName().c_str();
liyuqian1f508fd2016-06-07 06:57:40 -0700425 if (fAllSlideNames.size() == 0) {
426 for(auto slide : fSlides) {
427 fAllSlideNames.append(Json::Value(slide->getName().c_str()));
428 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700429 }
liyuqian1f508fd2016-06-07 06:57:40 -0700430 slideState[kOptions] = fAllSlideNames;
liyuqiane5a6cd92016-05-27 08:52:52 -0700431
liyuqianb73c24b2016-06-03 08:47:23 -0700432 // Backend state
liyuqiane5a6cd92016-05-27 08:52:52 -0700433 Json::Value backendState(Json::objectValue);
434 backendState[kName] = kBackendStateName;
liyuqian6cb70252016-06-02 12:16:25 -0700435 backendState[kValue] = kBackendTypeStrings[fBackendType];
liyuqiane5a6cd92016-05-27 08:52:52 -0700436 backendState[kOptions] = Json::Value(Json::arrayValue);
liyuqianb73c24b2016-06-03 08:47:23 -0700437 for (auto str : kBackendTypeStrings) {
liyuqian6cb70252016-06-02 12:16:25 -0700438 backendState[kOptions].append(Json::Value(str));
439 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700440
liyuqianb73c24b2016-06-03 08:47:23 -0700441 // Softkey state
442 Json::Value softkeyState(Json::objectValue);
443 softkeyState[kName] = kSoftkeyStateName;
444 softkeyState[kValue] = kSoftkeyHint;
445 softkeyState[kOptions] = Json::Value(Json::arrayValue);
446 softkeyState[kOptions].append(kSoftkeyHint);
447 for (const auto& softkey : fCommands.getCommandsAsSoftkeys()) {
448 softkeyState[kOptions].append(Json::Value(softkey.c_str()));
449 }
450
liyuqian1f508fd2016-06-07 06:57:40 -0700451 // FPS state
452 Json::Value fpsState(Json::objectValue);
453 fpsState[kName] = kFpsStateName;
454 double measurement = fMeasurements[
455 (fCurrentMeasurement + (kMeasurementCount-1)) % kMeasurementCount
456 ];
457 fpsState[kValue] = SkStringPrintf("%8.3lf ms", measurement).c_str();
458 fpsState[kOptions] = Json::Value(Json::arrayValue);
459
liyuqiane5a6cd92016-05-27 08:52:52 -0700460 Json::Value state(Json::arrayValue);
461 state.append(slideState);
462 state.append(backendState);
liyuqianb73c24b2016-06-03 08:47:23 -0700463 state.append(softkeyState);
liyuqian1f508fd2016-06-07 06:57:40 -0700464 state.append(fpsState);
liyuqiane5a6cd92016-05-27 08:52:52 -0700465
466 fWindow->setUIState(state);
467}
468
469void Viewer::onUIStateChanged(const SkString& stateName, const SkString& stateValue) {
liyuqian6cb70252016-06-02 12:16:25 -0700470 // For those who will add more features to handle the state change in this function:
471 // After the change, please call updateUIState no notify the frontend (e.g., Android app).
472 // For example, after slide change, updateUIState is called inside setupCurrentSlide;
473 // after backend change, updateUIState is called in this function.
liyuqiane5a6cd92016-05-27 08:52:52 -0700474 if (stateName.equals(kSlideStateName)) {
475 int previousSlide = fCurrentSlide;
476 fCurrentSlide = 0;
477 for(auto slide : fSlides) {
478 if (slide->getName().equals(stateValue)) {
479 setupCurrentSlide(previousSlide);
480 break;
481 }
482 fCurrentSlide++;
483 }
484 if (fCurrentSlide >= fSlides.count()) {
485 fCurrentSlide = previousSlide;
486 SkDebugf("Slide not found: %s", stateValue.c_str());
487 }
liyuqian6cb70252016-06-02 12:16:25 -0700488 } else if (stateName.equals(kBackendStateName)) {
489 for (int i = 0; i < sk_app::Window::kBackendTypeCount; i++) {
490 if (stateValue.equals(kBackendTypeStrings[i])) {
491 if (fBackendType != i) {
492 fBackendType = (sk_app::Window::BackendType)i;
493 fWindow->detach();
494 fWindow->attach(fBackendType, DisplayParams());
495 fWindow->inval();
496 updateTitle();
497 updateUIState();
498 }
499 break;
500 }
501 }
liyuqianb73c24b2016-06-03 08:47:23 -0700502 } else if (stateName.equals(kSoftkeyStateName)) {
503 if (!stateValue.equals(kSoftkeyHint)) {
504 fCommands.onSoftkey(stateValue);
505 updateUIState(); // This is still needed to reset the value to kSoftkeyHint
506 }
liyuqiane5a6cd92016-05-27 08:52:52 -0700507 } else {
508 SkDebugf("Unknown stateName: %s", stateName.c_str());
509 }
510}