1 /*
2  * Copyright 2012 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 
8 #include "SkDebuggerGUI.h"
9 #include "PictureRenderer.h"
10 #include "SkPictureData.h"
11 #include "SkPicturePlayback.h"
12 #include "SkPictureRecord.h"
13 #include <QListWidgetItem>
14 #include <QtGui>
15 #include "sk_tool_utils.h"
16 
17 #if defined(SK_BUILD_FOR_WIN32)
18     #include "SysTimer_windows.h"
19 #elif defined(SK_BUILD_FOR_MAC)
20     #include "SysTimer_mach.h"
21 #elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
22     #include "SysTimer_posix.h"
23 #else
24     #include "SysTimer_c.h"
25 #endif
26 
27 
SkDebuggerGUI(QWidget * parent)28 SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) :
29         QMainWindow(parent)
30     , fCentralSplitter(this)
31     , fStatusBar(this)
32     , fToolBar(this)
33     , fActionOpen(this)
34     , fActionBreakpoint(this)
35     , fActionProfile(this)
36     , fActionCancel(this)
37     , fActionClearBreakpoints(this)
38     , fActionClearDeletes(this)
39     , fActionClose(this)
40     , fActionCreateBreakpoint(this)
41     , fActionDelete(this)
42     , fActionDirectory(this)
43     , fActionGoToLine(this)
44     , fActionInspector(this)
45     , fActionSettings(this)
46     , fActionPlay(this)
47     , fActionPause(this)
48     , fActionRewind(this)
49     , fActionSave(this)
50     , fActionSaveAs(this)
51     , fActionShowDeletes(this)
52     , fActionStepBack(this)
53     , fActionStepForward(this)
54     , fActionZoomIn(this)
55     , fActionZoomOut(this)
56     , fMapper(this)
57     , fListWidget(&fCentralSplitter)
58     , fDirectoryWidget(&fCentralSplitter)
59     , fCanvasWidget(this, &fDebugger)
60     , fDrawCommandGeometryWidget(&fDebugger)
61     , fMenuBar(this)
62     , fMenuFile(this)
63     , fMenuNavigate(this)
64     , fMenuView(this)
65     , fLoading(false)
66 {
67     setupUi(this);
68     fListWidget.setSelectionMode(QAbstractItemView::ExtendedSelection);
69     connect(&fListWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this,
70             SLOT(updateDrawCommandInfo()));
71     connect(&fActionOpen, SIGNAL(triggered()), this, SLOT(openFile()));
72     connect(&fActionDirectory, SIGNAL(triggered()), this, SLOT(toggleDirectory()));
73     connect(&fDirectoryWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(loadFile(QListWidgetItem *)));
74     connect(&fActionDelete, SIGNAL(triggered()), this, SLOT(actionDelete()));
75     connect(&fListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(toggleBreakpoint()));
76     connect(&fActionRewind, SIGNAL(triggered()), this, SLOT(actionRewind()));
77     connect(&fActionPlay, SIGNAL(triggered()), this, SLOT(actionPlay()));
78     connect(&fActionStepBack, SIGNAL(triggered()), this, SLOT(actionStepBack()));
79     connect(&fActionStepForward, SIGNAL(triggered()), this, SLOT(actionStepForward()));
80     connect(&fActionBreakpoint, SIGNAL(triggered()), this, SLOT(actionBreakpoints()));
81     connect(&fActionInspector, SIGNAL(triggered()), this, SLOT(actionInspector()));
82     connect(&fActionSettings, SIGNAL(triggered()), this, SLOT(actionSettings()));
83     connect(&fFilter, SIGNAL(activated(QString)), this, SLOT(toggleFilter(QString)));
84     connect(&fActionProfile, SIGNAL(triggered()), this, SLOT(actionProfile()));
85     connect(&fActionCancel, SIGNAL(triggered()), this, SLOT(actionCancel()));
86     connect(&fActionClearBreakpoints, SIGNAL(triggered()), this, SLOT(actionClearBreakpoints()));
87     connect(&fActionClearDeletes, SIGNAL(triggered()), this, SLOT(actionClearDeletes()));
88     connect(&fActionClose, SIGNAL(triggered()), this, SLOT(actionClose()));
89 #if SK_SUPPORT_GPU
90     connect(&fSettingsWidget, SIGNAL(glSettingsChanged()), this, SLOT(actionGLSettingsChanged()));
91 #endif
92     connect(&fSettingsWidget, SIGNAL(rasterSettingsChanged()), this, SLOT(actionRasterSettingsChanged()));
93     connect(&fSettingsWidget, SIGNAL(visualizationsChanged()), this, SLOT(actionVisualizationsChanged()));
94     connect(&fSettingsWidget, SIGNAL(texFilterSettingsChanged()), this, SLOT(actionTextureFilter()));
95     connect(&fActionPause, SIGNAL(toggled(bool)), this, SLOT(pauseDrawing(bool)));
96     connect(&fActionCreateBreakpoint, SIGNAL(activated()), this, SLOT(toggleBreakpoint()));
97     connect(&fActionShowDeletes, SIGNAL(triggered()), this, SLOT(showDeletes()));
98     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), this, SLOT(selectCommand(int)));
99     connect(&fCanvasWidget, SIGNAL(hitChanged(int)), this, SLOT(updateHit(int)));
100     connect(&fCanvasWidget, SIGNAL(scaleFactorChanged(float)), this, SLOT(actionScale(float)));
101 
102     connect(&fActionSaveAs, SIGNAL(triggered()), this, SLOT(actionSaveAs()));
103     connect(&fActionSave, SIGNAL(triggered()), this, SLOT(actionSave()));
104 
105     fMapper.setMapping(&fActionZoomIn, SkCanvasWidget::kIn_ZoomCommand);
106     fMapper.setMapping(&fActionZoomOut, SkCanvasWidget::kOut_ZoomCommand);
107 
108     connect(&fActionZoomIn, SIGNAL(triggered()), &fMapper, SLOT(map()));
109     connect(&fActionZoomOut, SIGNAL(triggered()), &fMapper, SLOT(map()));
110     connect(&fMapper, SIGNAL(mapped(int)), &fCanvasWidget, SLOT(zoom(int)));
111 
112     fViewStateFrame.setDisabled(true);
113     fInspectorWidget.setDisabled(true);
114     fMenuEdit.setDisabled(true);
115     fMenuNavigate.setDisabled(true);
116     fMenuView.setDisabled(true);
117 }
118 
actionBreakpoints()119 void SkDebuggerGUI::actionBreakpoints() {
120     bool breakpointsActivated = fActionBreakpoint.isChecked();
121     for (int row = 0; row < fListWidget.count(); row++) {
122         QListWidgetItem *item = fListWidget.item(row);
123         item->setHidden(item->checkState() == Qt::Unchecked && breakpointsActivated);
124     }
125 }
126 
showDeletes()127 void SkDebuggerGUI::showDeletes() {
128     bool deletesActivated = fActionShowDeletes.isChecked();
129     for (int row = 0; row < fListWidget.count(); row++) {
130         QListWidgetItem *item = fListWidget.item(row);
131         item->setHidden(fDebugger.isCommandVisible(row) && deletesActivated);
132     }
133 }
134 // This is a simplification of PictureBenchmark's run with the addition of
135 // clearing of the times after the first pass (in resetTimes)
run(const SkPicture * pict,sk_tools::PictureRenderer * renderer,int repeats)136 void SkDebuggerGUI::run(const SkPicture* pict,
137                         sk_tools::PictureRenderer* renderer,
138                         int repeats) {
139     SkASSERT(pict);
140     if (NULL == pict) {
141         return;
142     }
143 
144     SkASSERT(renderer != NULL);
145     if (NULL == renderer) {
146         return;
147     }
148 
149     renderer->init(pict, NULL, NULL, NULL, false, false);
150 
151     renderer->setup();
152     renderer->render();
153     renderer->resetState(true);    // flush, swapBuffers and Finish
154 
155     for (int i = 0; i < repeats; ++i) {
156         renderer->setup();
157         renderer->render();
158         renderer->resetState(false);  // flush & swapBuffers, but don't Finish
159     }
160     renderer->resetState(true);    // flush, swapBuffers and Finish
161 
162     renderer->end();
163 }
164 
actionProfile()165 void SkDebuggerGUI::actionProfile() {
166     // In order to profile we pass the command offsets (that were read-in
167     // in loadPicture by the SkOffsetPicture) to an SkTimedPlaybackPicture.
168     // The SkTimedPlaybackPicture in turn passes the offsets to an
169     // SkTimedPicturePlayback object which uses them to track the performance
170     // of individual commands.
171     if (fFileName.isEmpty()) {
172         return;
173     }
174 
175     SkFILEStream inputStream;
176 
177     inputStream.setPath(fFileName.c_str());
178     if (!inputStream.isValid()) {
179         return;
180     }
181 
182     SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream,
183                                         &SkImageDecoder::DecodeMemory)); // , fSkipCommands));
184     if (NULL == picture.get()) {
185         return;
186     }
187 }
188 
actionCancel()189 void SkDebuggerGUI::actionCancel() {
190     for (int row = 0; row < fListWidget.count(); row++) {
191         fListWidget.item(row)->setHidden(false);
192     }
193 }
194 
actionClearBreakpoints()195 void SkDebuggerGUI::actionClearBreakpoints() {
196     for (int row = 0; row < fListWidget.count(); row++) {
197         QListWidgetItem* item = fListWidget.item(row);
198         item->setCheckState(Qt::Unchecked);
199         item->setData(Qt::DecorationRole,
200                 QPixmap(":/blank.png"));
201     }
202 }
203 
actionClearDeletes()204 void SkDebuggerGUI::actionClearDeletes() {
205     for (int row = 0; row < fListWidget.count(); row++) {
206         QListWidgetItem* item = fListWidget.item(row);
207         item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
208         fDebugger.setCommandVisible(row, true);
209         fSkipCommands[row] = false;
210     }
211     this->updateImage();
212 }
213 
actionClose()214 void SkDebuggerGUI::actionClose() {
215     this->close();
216 }
217 
actionDelete()218 void SkDebuggerGUI::actionDelete() {
219 
220     for (int row = 0; row < fListWidget.count(); ++row) {
221         QListWidgetItem* item = fListWidget.item(row);
222 
223         if (!item->isSelected()) {
224             continue;
225         }
226 
227         if (fDebugger.isCommandVisible(row)) {
228             item->setData(Qt::UserRole + 2, QPixmap(":/delete.png"));
229             fDebugger.setCommandVisible(row, false);
230             fSkipCommands[row] = true;
231         } else {
232             item->setData(Qt::UserRole + 2, QPixmap(":/blank.png"));
233             fDebugger.setCommandVisible(row, true);
234             fSkipCommands[row] = false;
235         }
236     }
237 
238     this->updateImage();
239 }
240 
241 #if SK_SUPPORT_GPU
actionGLSettingsChanged()242 void SkDebuggerGUI::actionGLSettingsChanged() {
243     bool isToggled = fSettingsWidget.isGLActive();
244     if (isToggled) {
245         fCanvasWidget.setGLSampleCount(fSettingsWidget.getGLSampleCount());
246     }
247     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kGPU_WidgetType, !isToggled);
248 }
249 #endif
250 
actionInspector()251 void SkDebuggerGUI::actionInspector() {
252     bool newState = !fInspectorWidget.isHidden();
253 
254     fInspectorWidget.setHidden(newState);
255     fViewStateFrame.setHidden(newState);
256     fDrawCommandGeometryWidget.setHidden(newState);
257 }
258 
actionPlay()259 void SkDebuggerGUI::actionPlay() {
260     for (int row = fListWidget.currentRow() + 1; row < fListWidget.count();
261             row++) {
262         QListWidgetItem *item = fListWidget.item(row);
263         if (item->checkState() == Qt::Checked) {
264             fListWidget.setCurrentItem(item);
265             return;
266         }
267     }
268     fListWidget.setCurrentRow(fListWidget.count() - 1);
269 }
270 
actionRasterSettingsChanged()271 void SkDebuggerGUI::actionRasterSettingsChanged() {
272     fCanvasWidget.setWidgetVisibility(SkCanvasWidget::kRaster_8888_WidgetType,
273                                       !fSettingsWidget.isRasterEnabled());
274     fDebugger.setOverdrawViz(fSettingsWidget.isOverdrawVizEnabled());
275     this->updateImage();
276 }
277 
actionVisualizationsChanged()278 void SkDebuggerGUI::actionVisualizationsChanged() {
279     fDebugger.setMegaViz(fSettingsWidget.isMegaVizEnabled());
280     fDebugger.setPathOps(fSettingsWidget.isPathOpsEnabled());
281     fDebugger.highlightCurrentCommand(fSettingsWidget.isVisibilityFilterEnabled());
282     this->updateImage();
283 }
284 
actionTextureFilter()285 void SkDebuggerGUI::actionTextureFilter() {
286     SkFilterQuality quality;
287     bool enabled = fSettingsWidget.getFilterOverride(&quality);
288     fDebugger.setTexFilterOverride(enabled, quality);
289     fCanvasWidget.update();
290 }
291 
actionRewind()292 void SkDebuggerGUI::actionRewind() {
293     fListWidget.setCurrentRow(0);
294 }
295 
actionSave()296 void SkDebuggerGUI::actionSave() {
297     fFileName = fPath.toAscii().data();
298     fFileName.append("/");
299     fFileName.append(fDirectoryWidget.currentItem()->text().toAscii().data());
300     saveToFile(fFileName);
301 }
302 
actionSaveAs()303 void SkDebuggerGUI::actionSaveAs() {
304     QString filename = QFileDialog::getSaveFileName(this, "Save File", "",
305             "Skia Picture (*skp)");
306     if (!filename.endsWith(".skp", Qt::CaseInsensitive)) {
307         filename.append(".skp");
308     }
309     saveToFile(SkString(filename.toAscii().data()));
310 }
311 
actionScale(float scaleFactor)312 void SkDebuggerGUI::actionScale(float scaleFactor) {
313     fZoomBox.setText(QString::number(scaleFactor * 100, 'f', 0).append("%"));
314 }
315 
actionSettings()316 void SkDebuggerGUI::actionSettings() {
317     if (fSettingsWidget.isHidden()) {
318         fSettingsWidget.setHidden(false);
319     } else {
320         fSettingsWidget.setHidden(true);
321     }
322 }
323 
actionStepBack()324 void SkDebuggerGUI::actionStepBack() {
325     int currentRow = fListWidget.currentRow();
326     if (currentRow != 0) {
327         fListWidget.setCurrentRow(currentRow - 1);
328     }
329 }
330 
actionStepForward()331 void SkDebuggerGUI::actionStepForward() {
332     int currentRow = fListWidget.currentRow();
333     QString curRow = QString::number(currentRow);
334     QString curCount = QString::number(fListWidget.count());
335     if (currentRow < fListWidget.count() - 1) {
336         fListWidget.setCurrentRow(currentRow + 1);
337     }
338 }
339 
drawComplete()340 void SkDebuggerGUI::drawComplete() {
341     SkString clipStack;
342     fDebugger.getClipStackText(&clipStack);
343     fInspectorWidget.setText(clipStack.c_str(), SkInspectorWidget::kClipStack_TabType);
344 
345     fInspectorWidget.setMatrix(fDebugger.getCurrentMatrix());
346     fInspectorWidget.setClip(fDebugger.getCurrentClip());
347 }
348 
saveToFile(const SkString & filename)349 void SkDebuggerGUI::saveToFile(const SkString& filename) {
350     SkFILEWStream file(filename.c_str());
351     SkAutoTUnref<SkPicture> copy(fDebugger.copyPicture());
352 
353     sk_tool_utils::PngPixelSerializer serializer;
354     copy->serialize(&file, &serializer);
355 }
356 
loadFile(QListWidgetItem * item)357 void SkDebuggerGUI::loadFile(QListWidgetItem *item) {
358     if (fDirectoryWidgetActive) {
359         fFileName = fPath.toAscii().data();
360         // don't add a '/' to files in the local directory
361         if (fFileName.size() > 0) {
362             fFileName.append("/");
363         }
364         fFileName.append(item->text().toAscii().data());
365         loadPicture(fFileName);
366     }
367 }
368 
openFile()369 void SkDebuggerGUI::openFile() {
370     QString temp = QFileDialog::getOpenFileName(this, tr("Open File"), "",
371             tr("Files (*.*)"));
372     openFile(temp);
373 }
374 
openFile(const QString & filename)375 void SkDebuggerGUI::openFile(const QString &filename) {
376     fDirectoryWidgetActive = false;
377     if (!filename.isEmpty()) {
378         QFileInfo pathInfo(filename);
379         loadPicture(SkString(filename.toAscii().data()));
380         setupDirectoryWidget(pathInfo.path());
381     }
382     fDirectoryWidgetActive = true;
383 }
384 
pauseDrawing(bool isPaused)385 void SkDebuggerGUI::pauseDrawing(bool isPaused) {
386     fPausedRow = fListWidget.currentRow();
387     this->updateDrawCommandInfo();
388 }
389 
updateDrawCommandInfo()390 void SkDebuggerGUI::updateDrawCommandInfo() {
391     int currentRow = -1;
392     if (!fLoading) {
393         currentRow = fListWidget.currentRow();
394     }
395     if (currentRow == -1) {
396         fInspectorWidget.setText("", SkInspectorWidget::kDetail_TabType);
397         fInspectorWidget.setText("", SkInspectorWidget::kClipStack_TabType);
398         fCurrentCommandBox.setText("");
399         fDrawCommandGeometryWidget.setDrawCommandIndex(-1);
400     } else {
401         this->updateImage();
402 
403         const SkTDArray<SkString*> *currInfo = fDebugger.getCommandInfo(currentRow);
404 
405         /* TODO(chudy): Add command type before parameters. Rename v
406          * to something more informative. */
407         if (currInfo) {
408             QString info;
409             info.append("<b>Parameters: </b><br/>");
410             for (int i = 0; i < currInfo->count(); i++) {
411                 info.append(QString((*currInfo)[i]->c_str()));
412                 info.append("<br/>");
413             }
414             fInspectorWidget.setText(info, SkInspectorWidget::kDetail_TabType);
415         }
416 
417         fCurrentCommandBox.setText(QString::number(currentRow));
418 
419         fDrawCommandGeometryWidget.setDrawCommandIndex(currentRow);
420 
421         fInspectorWidget.setDisabled(false);
422         fViewStateFrame.setDisabled(false);
423     }
424 }
425 
selectCommand(int command)426 void SkDebuggerGUI::selectCommand(int command) {
427     if (this->isPaused()) {
428         fListWidget.setCurrentRow(command);
429     }
430 }
431 
toggleBreakpoint()432 void SkDebuggerGUI::toggleBreakpoint() {
433     QListWidgetItem* item = fListWidget.currentItem();
434     if (item->checkState() == Qt::Unchecked) {
435         item->setCheckState(Qt::Checked);
436         item->setData(Qt::DecorationRole,
437                 QPixmap(":/breakpoint_16x16.png"));
438     } else {
439         item->setCheckState(Qt::Unchecked);
440         item->setData(Qt::DecorationRole,
441                 QPixmap(":/blank.png"));
442     }
443 }
444 
toggleDirectory()445 void SkDebuggerGUI::toggleDirectory() {
446     fDirectoryWidget.setHidden(!fDirectoryWidget.isHidden());
447 }
448 
toggleFilter(QString string)449 void SkDebuggerGUI::toggleFilter(QString string) {
450     for (int row = 0; row < fListWidget.count(); row++) {
451         QListWidgetItem *item = fListWidget.item(row);
452         item->setHidden(item->text() != string);
453     }
454 }
455 
setupUi(QMainWindow * SkDebuggerGUI)456 void SkDebuggerGUI::setupUi(QMainWindow *SkDebuggerGUI) {
457     QIcon windowIcon;
458     windowIcon.addFile(QString::fromUtf8(":/skia.png"), QSize(),
459             QIcon::Normal, QIcon::Off);
460     SkDebuggerGUI->setObjectName(QString::fromUtf8("SkDebuggerGUI"));
461     SkDebuggerGUI->resize(1200, 1000);
462     SkDebuggerGUI->setWindowIcon(windowIcon);
463     SkDebuggerGUI->setWindowTitle("Skia Debugger");
464 
465     fActionOpen.setShortcuts(QKeySequence::Open);
466     fActionOpen.setText("Open");
467 
468     QIcon breakpoint;
469     breakpoint.addFile(QString::fromUtf8(":/breakpoint.png"),
470             QSize(), QIcon::Normal, QIcon::Off);
471     fActionBreakpoint.setShortcut(QKeySequence(tr("Ctrl+B")));
472     fActionBreakpoint.setIcon(breakpoint);
473     fActionBreakpoint.setText("Breakpoints");
474     fActionBreakpoint.setCheckable(true);
475 
476     QIcon cancel;
477     cancel.addFile(QString::fromUtf8(":/reload.png"), QSize(),
478             QIcon::Normal, QIcon::Off);
479     fActionCancel.setIcon(cancel);
480     fActionCancel.setText("Clear Filter");
481 
482     fActionClearBreakpoints.setShortcut(QKeySequence(tr("Alt+B")));
483     fActionClearBreakpoints.setText("Clear Breakpoints");
484 
485     fActionClearDeletes.setShortcut(QKeySequence(tr("Alt+X")));
486     fActionClearDeletes.setText("Clear Deletes");
487 
488     fActionClose.setShortcuts(QKeySequence::Quit);
489     fActionClose.setText("Exit");
490 
491     fActionCreateBreakpoint.setShortcut(QKeySequence(tr("B")));
492     fActionCreateBreakpoint.setText("Set Breakpoint");
493 
494     fActionDelete.setShortcut(QKeySequence(tr("X")));
495     fActionDelete.setText("Delete Command");
496 
497     fActionDirectory.setShortcut(QKeySequence(tr("Ctrl+D")));
498     fActionDirectory.setText("Directory");
499 
500     QIcon profile;
501     profile.addFile(QString::fromUtf8(":/profile.png"), QSize(),
502                     QIcon::Normal, QIcon::Off);
503     fActionProfile.setIcon(profile);
504     fActionProfile.setText("Profile");
505     fActionProfile.setDisabled(true);
506 
507     QIcon inspector;
508     inspector.addFile(QString::fromUtf8(":/inspector.png"),
509             QSize(), QIcon::Normal, QIcon::Off);
510     fActionInspector.setShortcut(QKeySequence(tr("Ctrl+I")));
511     fActionInspector.setIcon(inspector);
512     fActionInspector.setText("Inspector");
513 
514     QIcon settings;
515     settings.addFile(QString::fromUtf8(":/inspector.png"),
516             QSize(), QIcon::Normal, QIcon::Off);
517     fActionSettings.setShortcut(QKeySequence(tr("Ctrl+G")));
518     fActionSettings.setIcon(settings);
519     fActionSettings.setText("Settings");
520 
521     QIcon play;
522     play.addFile(QString::fromUtf8(":/play.png"), QSize(),
523             QIcon::Normal, QIcon::Off);
524     fActionPlay.setShortcut(QKeySequence(tr("Ctrl+P")));
525     fActionPlay.setIcon(play);
526     fActionPlay.setText("Play");
527 
528     QIcon pause;
529     pause.addFile(QString::fromUtf8(":/pause.png"), QSize(),
530             QIcon::Normal, QIcon::Off);
531     fActionPause.setShortcut(QKeySequence(tr("Space")));
532     fActionPause.setCheckable(true);
533     fActionPause.setIcon(pause);
534     fActionPause.setText("Pause");
535 
536     QIcon rewind;
537     rewind.addFile(QString::fromUtf8(":/rewind.png"), QSize(),
538             QIcon::Normal, QIcon::Off);
539     fActionRewind.setShortcut(QKeySequence(tr("Ctrl+R")));
540     fActionRewind.setIcon(rewind);
541     fActionRewind.setText("Rewind");
542 
543     fActionSave.setShortcut(QKeySequence::Save);
544     fActionSave.setText("Save");
545     fActionSave.setDisabled(true);
546     fActionSaveAs.setShortcut(QKeySequence::SaveAs);
547     fActionSaveAs.setText("Save As");
548     fActionSaveAs.setDisabled(true);
549 
550     fActionShowDeletes.setShortcut(QKeySequence(tr("Ctrl+X")));
551     fActionShowDeletes.setText("Deleted Commands");
552     fActionShowDeletes.setCheckable(true);
553 
554     QIcon stepBack;
555     stepBack.addFile(QString::fromUtf8(":/previous.png"), QSize(),
556             QIcon::Normal, QIcon::Off);
557     fActionStepBack.setShortcut(QKeySequence(tr("[")));
558     fActionStepBack.setIcon(stepBack);
559     fActionStepBack.setText("Step Back");
560 
561     QIcon stepForward;
562     stepForward.addFile(QString::fromUtf8(":/next.png"),
563             QSize(), QIcon::Normal, QIcon::Off);
564     fActionStepForward.setShortcut(QKeySequence(tr("]")));
565     fActionStepForward.setIcon(stepForward);
566     fActionStepForward.setText("Step Forward");
567 
568     fActionZoomIn.setShortcut(QKeySequence(tr("Ctrl+=")));
569     fActionZoomIn.setText("Zoom In");
570     fActionZoomOut.setShortcut(QKeySequence(tr("Ctrl+-")));
571     fActionZoomOut.setText("Zoom Out");
572 
573     fListWidget.setItemDelegate(new SkListWidget(&fListWidget));
574     fListWidget.setObjectName(QString::fromUtf8("listWidget"));
575     fListWidget.setMinimumWidth(250);
576 
577     fFilter.addItem("--Filter By Available Commands--");
578 
579     fDirectoryWidget.setMinimumWidth(250);
580     fDirectoryWidget.setStyleSheet("QListWidget::Item {padding: 5px;}");
581 
582     fCanvasWidget.setSizePolicy(QSizePolicy::Expanding,
583             QSizePolicy::Expanding);
584 
585     fDrawCommandGeometryWidget.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
586 
587     fSettingsAndImageLayout.addWidget(&fSettingsWidget);
588 
589     // View state group, part of inspector.
590     fViewStateFrame.setFrameStyle(QFrame::Panel);
591     fViewStateFrame.setLayout(&fViewStateFrameLayout);
592     fViewStateFrameLayout.addWidget(&fViewStateGroup);
593     fViewStateGroup.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
594     fViewStateGroup.setTitle("View");
595     fViewStateLayout.addRow("Zoom Level", &fZoomBox);
596     fZoomBox.setText("100%");
597     fZoomBox.setMinimumSize(QSize(50,25));
598     fZoomBox.setMaximumSize(QSize(50,25));
599     fZoomBox.setAlignment(Qt::AlignRight);
600     fZoomBox.setReadOnly(true);
601     fViewStateLayout.addRow("Command HitBox", &fCommandHitBox);
602     fCommandHitBox.setText("0");
603     fCommandHitBox.setMinimumSize(QSize(50,25));
604     fCommandHitBox.setMaximumSize(QSize(50,25));
605     fCommandHitBox.setAlignment(Qt::AlignRight);
606     fCommandHitBox.setReadOnly(true);
607     fViewStateLayout.addRow("Current Command", &fCurrentCommandBox);
608     fCurrentCommandBox.setText("0");
609     fCurrentCommandBox.setMinimumSize(QSize(50,25));
610     fCurrentCommandBox.setMaximumSize(QSize(50,25));
611     fCurrentCommandBox.setAlignment(Qt::AlignRight);
612     fCurrentCommandBox.setReadOnly(true);
613     fViewStateGroup.setLayout(&fViewStateLayout);
614     fSettingsAndImageLayout.addWidget(&fViewStateFrame);
615 
616     fDrawCommandGeometryWidget.setToolTip("Current Command Geometry");
617     fSettingsAndImageLayout.addWidget(&fDrawCommandGeometryWidget);
618 
619     fLeftColumnSplitter.addWidget(&fListWidget);
620     fLeftColumnSplitter.addWidget(&fDirectoryWidget);
621     fLeftColumnSplitter.setOrientation(Qt::Vertical);
622 
623     fCanvasSettingsAndImageLayout.setSpacing(6);
624     fCanvasSettingsAndImageLayout.addWidget(&fCanvasWidget, 1);
625     fCanvasSettingsAndImageLayout.addLayout(&fSettingsAndImageLayout, 0);
626 
627     fMainAndRightColumnLayout.setSpacing(6);
628     fMainAndRightColumnLayout.addLayout(&fCanvasSettingsAndImageLayout, 1);
629     fMainAndRightColumnLayout.addWidget(&fInspectorWidget, 0);
630     fMainAndRightColumnWidget.setLayout(&fMainAndRightColumnLayout);
631 
632     fCentralSplitter.addWidget(&fLeftColumnSplitter);
633     fCentralSplitter.addWidget(&fMainAndRightColumnWidget);
634     fCentralSplitter.setStretchFactor(0, 0);
635     fCentralSplitter.setStretchFactor(1, 1);
636 
637     SkDebuggerGUI->setCentralWidget(&fCentralSplitter);
638     SkDebuggerGUI->setStatusBar(&fStatusBar);
639 
640     fToolBar.setIconSize(QSize(32, 32));
641     fToolBar.setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
642     SkDebuggerGUI->addToolBar(Qt::TopToolBarArea, &fToolBar);
643 
644     fSpacer.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
645 
646     fToolBar.addAction(&fActionRewind);
647     fToolBar.addAction(&fActionStepBack);
648     fToolBar.addAction(&fActionPause);
649     fToolBar.addAction(&fActionStepForward);
650     fToolBar.addAction(&fActionPlay);
651     fToolBar.addSeparator();
652     fToolBar.addAction(&fActionInspector);
653     fToolBar.addAction(&fActionSettings);
654     fToolBar.addSeparator();
655     fToolBar.addAction(&fActionProfile);
656 
657     fToolBar.addSeparator();
658     fToolBar.addWidget(&fSpacer);
659     fToolBar.addWidget(&fFilter);
660     fToolBar.addAction(&fActionCancel);
661 
662     // TODO(chudy): Remove static call.
663     fDirectoryWidgetActive = false;
664     fFileName = "";
665     setupDirectoryWidget("");
666     fDirectoryWidgetActive = true;
667 
668     // Menu Bar
669     fMenuFile.setTitle("File");
670     fMenuFile.addAction(&fActionOpen);
671     fMenuFile.addAction(&fActionSave);
672     fMenuFile.addAction(&fActionSaveAs);
673     fMenuFile.addAction(&fActionClose);
674 
675     fMenuEdit.setTitle("Edit");
676     fMenuEdit.addAction(&fActionDelete);
677     fMenuEdit.addAction(&fActionClearDeletes);
678     fMenuEdit.addSeparator();
679     fMenuEdit.addAction(&fActionCreateBreakpoint);
680     fMenuEdit.addAction(&fActionClearBreakpoints);
681 
682     fMenuNavigate.setTitle("Navigate");
683     fMenuNavigate.addAction(&fActionRewind);
684     fMenuNavigate.addAction(&fActionStepBack);
685     fMenuNavigate.addAction(&fActionStepForward);
686     fMenuNavigate.addAction(&fActionPlay);
687     fMenuNavigate.addAction(&fActionPause);
688     fMenuNavigate.addAction(&fActionGoToLine);
689 
690     fMenuView.setTitle("View");
691     fMenuView.addAction(&fActionBreakpoint);
692     fMenuView.addAction(&fActionShowDeletes);
693     fMenuView.addAction(&fActionZoomIn);
694     fMenuView.addAction(&fActionZoomOut);
695 
696     fMenuWindows.setTitle("Window");
697     fMenuWindows.addAction(&fActionInspector);
698     fMenuWindows.addAction(&fActionSettings);
699     fMenuWindows.addAction(&fActionDirectory);
700 
701     fActionGoToLine.setText("Go to Line...");
702     fActionGoToLine.setDisabled(true);
703     fMenuBar.addAction(fMenuFile.menuAction());
704     fMenuBar.addAction(fMenuEdit.menuAction());
705     fMenuBar.addAction(fMenuView.menuAction());
706     fMenuBar.addAction(fMenuNavigate.menuAction());
707     fMenuBar.addAction(fMenuWindows.menuAction());
708 
709     SkDebuggerGUI->setMenuBar(&fMenuBar);
710     QMetaObject::connectSlotsByName(SkDebuggerGUI);
711 }
712 
setupDirectoryWidget(const QString & path)713 void SkDebuggerGUI::setupDirectoryWidget(const QString& path) {
714     fPath = path;
715     QDir dir(path);
716     QRegExp r(".skp");
717     fDirectoryWidget.clear();
718     const QStringList files = dir.entryList();
719     foreach (QString f, files) {
720         if (f.contains(r))
721             fDirectoryWidget.addItem(f);
722     }
723 }
724 
loadPicture(const SkString & fileName)725 void SkDebuggerGUI::loadPicture(const SkString& fileName) {
726     fFileName = fileName;
727     fLoading = true;
728     SkAutoTDelete<SkStream> stream(SkNEW_ARGS(SkFILEStream, (fileName.c_str())));
729 
730     SkPicture* picture = SkPicture::CreateFromStream(stream);
731 
732     if (NULL == picture) {
733         QMessageBox::critical(this, "Error loading file", "Couldn't read file, sorry.");
734         return;
735     }
736 
737     fCanvasWidget.resetWidgetTransform();
738     fDebugger.loadPicture(picture);
739 
740     fSkipCommands.setCount(fDebugger.getSize());
741     for (int i = 0; i < fSkipCommands.count(); ++i) {
742         fSkipCommands[i] = false;
743     }
744 
745     SkSafeUnref(picture);
746 
747     fActionProfile.setDisabled(false);
748 
749     /* fDebugCanvas is reinitialized every load picture. Need it to retain value
750      * of the visibility filter.
751      * TODO(chudy): This should be deprecated since fDebugger is not
752      * recreated.
753      * */
754     fDebugger.highlightCurrentCommand(fSettingsWidget.isVisibilityFilterEnabled());
755 
756     this->setupListWidget();
757     this->setupComboBox();
758     this->setupOverviewText(NULL, 0.0, 1);
759     fInspectorWidget.setDisabled(false);
760     fViewStateFrame.setDisabled(false);
761     fSettingsWidget.setDisabled(false);
762     fMenuEdit.setDisabled(false);
763     fMenuNavigate.setDisabled(false);
764     fMenuView.setDisabled(false);
765     fActionSave.setDisabled(false);
766     fActionSaveAs.setDisabled(false);
767     fActionPause.setChecked(false);
768     fDrawCommandGeometryWidget.setDrawCommandIndex(-1);
769 
770     fLoading = false;
771     actionPlay();
772 }
773 
setupListWidget()774 void SkDebuggerGUI::setupListWidget() {
775 
776     SkASSERT(!strcmp("Save",
777                      SkDrawCommand::GetCommandString(SkDrawCommand::kSave_OpType)));
778     SkASSERT(!strcmp("SaveLayer",
779                      SkDrawCommand::GetCommandString(SkDrawCommand::kSaveLayer_OpType)));
780     SkASSERT(!strcmp("Restore",
781                      SkDrawCommand::GetCommandString(SkDrawCommand::kRestore_OpType)));
782     SkASSERT(!strcmp("BeginCommentGroup",
783                      SkDrawCommand::GetCommandString(SkDrawCommand::kBeginCommentGroup_OpType)));
784     SkASSERT(!strcmp("EndCommentGroup",
785                      SkDrawCommand::GetCommandString(SkDrawCommand::kEndCommentGroup_OpType)));
786     SkASSERT(!strcmp("BeginDrawPicture",
787                      SkDrawCommand::GetCommandString(SkDrawCommand::kBeginDrawPicture_OpType)));
788     SkASSERT(!strcmp("EndDrawPicture",
789                      SkDrawCommand::GetCommandString(SkDrawCommand::kEndDrawPicture_OpType)));
790 
791     fListWidget.clear();
792     int counter = 0;
793     int indent = 0;
794     for (int i = 0; i < fDebugger.getSize(); i++) {
795         QListWidgetItem *item = new QListWidgetItem();
796         SkDrawCommand* command = fDebugger.getDrawCommandAt(i);
797         SkString commandString = command->toString();
798         item->setData(Qt::DisplayRole, commandString.c_str());
799         item->setData(Qt::UserRole + 1, counter++);
800 
801         if (0 == strcmp("Restore", commandString.c_str()) ||
802             0 == strcmp("EndCommentGroup", commandString.c_str()) ||
803             0 == strcmp("EndDrawPicture", commandString.c_str())) {
804             indent -= 10;
805         }
806 
807         item->setData(Qt::UserRole + 3, indent);
808 
809         if (0 == strcmp("Save", commandString.c_str()) ||
810             0 == strcmp("SaveLayer", commandString.c_str()) ||
811             0 == strcmp("BeginCommentGroup", commandString.c_str()) ||
812             0 == strcmp("BeginDrawPicture", commandString.c_str())) {
813             indent += 10;
814         }
815 
816         item->setData(Qt::UserRole + 4, -1);
817 
818         fListWidget.addItem(item);
819     }
820 }
821 
setupOverviewText(const SkTDArray<double> * typeTimes,double totTime,int numRuns)822 void SkDebuggerGUI::setupOverviewText(const SkTDArray<double>* typeTimes,
823                                       double totTime,
824                                       int numRuns) {
825     SkString overview;
826     fDebugger.getOverviewText(typeTimes, totTime, &overview, numRuns);
827     fInspectorWidget.setText(overview.c_str(), SkInspectorWidget::kOverview_TabType);
828 }
829 
830 
setupComboBox()831 void SkDebuggerGUI::setupComboBox() {
832     fFilter.clear();
833     fFilter.addItem("--Filter By Available Commands--");
834 
835     std::map<std::string, int> map;
836     for (int i = 0; i < fDebugger.getSize(); i++) {
837         map[fDebugger.getDrawCommandAt(i)->toString().c_str()]++;
838     }
839 
840     for (std::map<std::string, int>::iterator it = map.begin(); it != map.end();
841          ++it) {
842         fFilter.addItem((it->first).c_str());
843     }
844 
845     // NOTE(chudy): Makes first item unselectable.
846     QStandardItemModel* model = qobject_cast<QStandardItemModel*>(
847             fFilter.model());
848     QModelIndex firstIndex = model->index(0, fFilter.modelColumn(),
849             fFilter.rootModelIndex());
850     QStandardItem* firstItem = model->itemFromIndex(firstIndex);
851     firstItem->setSelectable(false);
852 }
853 
updateImage()854 void SkDebuggerGUI::updateImage() {
855     if (this->isPaused()) {
856         fCanvasWidget.drawTo(fPausedRow);
857     } else {
858         fCanvasWidget.drawTo(fListWidget.currentRow());
859     }
860 }
861 
updateHit(int newHit)862 void SkDebuggerGUI::updateHit(int newHit) {
863     fCommandHitBox.setText(QString::number(newHit));
864 }
865 
866