1 /*
2  * Copyright 2017 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 <memory>
9 
10 #include "Model.h"
11 
12 #include "SkBitmap.h"
13 #include "SkCanvas.h"
14 #include "SkDebugCanvas.h"
15 #include "SkPicture.h"
16 #include "SkStream.h"
17 
Model()18 Model::Model() : fCurOp(0) {
19     SkImageInfo ii = SkImageInfo::MakeN32Premul(1024, 1024);
20     fBM.allocPixels(ii, 0);
21 }
22 
~Model()23 Model::~Model() {
24     this->resetOpList();
25 }
26 
load(const char * filename)27 Model::ErrorCode Model::load(const char* filename) {
28     std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(filename);
29     if (!stream) {
30         return ErrorCode::kCouldntOpenFile;
31     }
32     sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get()));
33     if (!pic) {
34         return ErrorCode::kCouldntDecodeSKP;
35     }
36 
37     {
38         std::unique_ptr<SkDebugCanvas> temp(new SkDebugCanvas(
39                                                     SkScalarCeilToInt(pic->cullRect().width()),
40                                                     SkScalarCeilToInt(pic->cullRect().height())));
41 
42         temp->setPicture(pic.get());
43         pic->playback(temp.get());
44         temp->setPicture(nullptr);
45         this->resetOpList();
46         temp->detachCommands(&fOps);
47     }
48 
49     this->setCurOp(fOps.count()-1);
50 
51     return ErrorCode::kOK;
52 }
53 
ErrorString(ErrorCode err)54 const char* Model::ErrorString(ErrorCode err) {
55     static const char* kStrings[] = {
56         "OK",
57         "Couldn't read file",
58         "Couldn't decode picture"
59     };
60 
61     return kStrings[(int)err];
62 }
63 
getOpName(int index) const64 const char* Model::getOpName(int index) const {
65     return SkDrawCommand::GetCommandString(fOps[index]->getType());
66 }
67 
isHierarchyPush(int index) const68 bool Model::isHierarchyPush(int index) const {
69     SkDrawCommand::OpType type = fOps[index]->getType();
70 
71     return SkDrawCommand::kSave_OpType == type ||
72            SkDrawCommand::kSaveLayer_OpType == type ||
73            SkDrawCommand::kBeginDrawPicture_OpType == type;
74 }
75 
isHierarchyPop(int index) const76 bool Model::isHierarchyPop(int index) const {
77     SkDrawCommand::OpType type = fOps[index]->getType();
78 
79     return SkDrawCommand::kRestore_OpType == type ||
80            SkDrawCommand::kEndDrawPicture_OpType == type;
81 }
82 
setCurOp(int curOp)83 void Model::setCurOp(int curOp) {
84     SkASSERT(curOp < fOps.count());
85 
86     if (curOp == fCurOp) {
87         return; // the render state is already up to date
88     }
89 
90     fCurOp = curOp;
91     this->drawTo(fCurOp);
92 }
93 
drawTo(int index)94 void Model::drawTo(int index) {
95     SkASSERT(index < fOps.count());
96 
97     SkCanvas canvas(fBM);
98 
99     int saveCount = canvas.save();
100 
101     for (int i = 0; i <= index; ++i) {
102         if (fOps[i]->isVisible()) {
103             fOps[i]->execute(&canvas);
104         }
105     }
106 
107     canvas.restoreToCount(saveCount);
108 }
109 
resetOpList()110 void Model::resetOpList() {
111     for (int i = 0; i < fOps.count(); ++i) {
112         delete fOps[i];
113     }
114     fOps.reset();
115     fCurOp = 0;
116 }
117