1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/platform/graphics/picture_snapshot.h"
32
33 #include <memory>
34 #include "third_party/blink/renderer/platform/geometry/int_size.h"
35 #include "third_party/blink/renderer/platform/graphics/logging_canvas.h"
36 #include "third_party/blink/renderer/platform/graphics/profiling_canvas.h"
37 #include "third_party/blink/renderer/platform/graphics/replaying_canvas.h"
38 #include "third_party/blink/renderer/platform/graphics/skia/image_pixel_locker.h"
39 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
40 #include "third_party/blink/renderer/platform/image-decoders/image_frame.h"
41 #include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
42 #include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
43 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
44
45 #include "third_party/skia/include/core/SkImage.h"
46 #include "third_party/skia/include/core/SkPictureRecorder.h"
47
48 namespace blink {
49
PictureSnapshot(sk_sp<const SkPicture> picture)50 PictureSnapshot::PictureSnapshot(sk_sp<const SkPicture> picture)
51 : picture_(std::move(picture)) {}
52
Load(const Vector<scoped_refptr<TilePictureStream>> & tiles)53 scoped_refptr<PictureSnapshot> PictureSnapshot::Load(
54 const Vector<scoped_refptr<TilePictureStream>>& tiles) {
55 DCHECK(!tiles.IsEmpty());
56 Vector<sk_sp<SkPicture>> pictures;
57 pictures.ReserveCapacity(tiles.size());
58 FloatRect union_rect;
59 for (const auto& tile_stream : tiles) {
60 sk_sp<SkPicture> picture = std::move(tile_stream->picture);
61 if (!picture)
62 return nullptr;
63 FloatRect cull_rect(picture->cullRect());
64 cull_rect.MoveBy(tile_stream->layer_offset);
65 union_rect.Unite(cull_rect);
66 pictures.push_back(std::move(picture));
67 }
68 if (tiles.size() == 1)
69 return base::AdoptRef(new PictureSnapshot(std::move(pictures[0])));
70 SkPictureRecorder recorder;
71 SkCanvas* canvas = recorder.beginRecording(union_rect.Width(),
72 union_rect.Height(), nullptr, 0);
73 for (size_t i = 0; i < pictures.size(); ++i) {
74 canvas->save();
75 canvas->translate(tiles[i]->layer_offset.X() - union_rect.X(),
76 tiles[i]->layer_offset.Y() - union_rect.Y());
77 pictures[i]->playback(canvas, nullptr);
78 canvas->restore();
79 }
80 return base::AdoptRef(
81 new PictureSnapshot(recorder.finishRecordingAsPicture()));
82 }
83
IsEmpty() const84 bool PictureSnapshot::IsEmpty() const {
85 return picture_->cullRect().isEmpty();
86 }
87
Replay(unsigned from_step,unsigned to_step,double scale) const88 Vector<uint8_t> PictureSnapshot::Replay(unsigned from_step,
89 unsigned to_step,
90 double scale) const {
91 const SkIRect bounds = picture_->cullRect().roundOut();
92 int width = ceil(scale * bounds.width());
93 int height = ceil(scale * bounds.height());
94
95 // TODO(fmalita): convert this to SkSurface/SkImage, drop the intermediate
96 // SkBitmap.
97 SkBitmap bitmap;
98 bitmap.allocPixels(SkImageInfo::MakeN32Premul(width, height));
99 bitmap.eraseARGB(0, 0, 0, 0);
100 {
101 ReplayingCanvas canvas(bitmap, from_step, to_step);
102 // Disable LCD text preemptively, because the picture opacity is unknown.
103 // The canonical API involves SkSurface props, but since we're not
104 // SkSurface-based at this point (see TODO above) we (ab)use saveLayer for
105 // this purpose.
106 SkAutoCanvasRestore auto_restore(&canvas, false);
107 canvas.saveLayer(nullptr, nullptr);
108
109 canvas.scale(scale, scale);
110 canvas.ResetStepCount();
111 picture_->playback(&canvas, &canvas);
112 }
113 Vector<uint8_t> encoded_image;
114
115 SkPixmap src;
116 bool peekResult = bitmap.peekPixels(&src);
117 DCHECK(peekResult);
118
119 SkPngEncoder::Options options;
120 options.fFilterFlags = SkPngEncoder::FilterFlag::kSub;
121 options.fZLibLevel = 3;
122 if (!ImageEncoder::Encode(&encoded_image, src, options))
123 return Vector<uint8_t>();
124
125 return encoded_image;
126 }
127
Profile(unsigned min_repeat_count,base::TimeDelta min_duration,const FloatRect * clip_rect) const128 Vector<Vector<base::TimeDelta>> PictureSnapshot::Profile(
129 unsigned min_repeat_count,
130 base::TimeDelta min_duration,
131 const FloatRect* clip_rect) const {
132 Vector<Vector<base::TimeDelta>> timings;
133 timings.ReserveInitialCapacity(min_repeat_count);
134 const SkIRect bounds = picture_->cullRect().roundOut();
135 SkBitmap bitmap;
136 bitmap.allocPixels(
137 SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()));
138 bitmap.eraseARGB(0, 0, 0, 0);
139
140 base::TimeTicks now = base::TimeTicks::Now();
141 base::TimeTicks stop_time = now + min_duration;
142 for (unsigned step = 0; step < min_repeat_count || now < stop_time; ++step) {
143 Vector<base::TimeDelta> current_timings;
144 if (!timings.IsEmpty())
145 current_timings.ReserveInitialCapacity(timings.front().size());
146 ProfilingCanvas canvas(bitmap);
147 if (clip_rect) {
148 canvas.clipRect(SkRect::MakeXYWH(clip_rect->X(), clip_rect->Y(),
149 clip_rect->Width(),
150 clip_rect->Height()));
151 canvas.ResetStepCount();
152 }
153 canvas.SetTimings(¤t_timings);
154 picture_->playback(&canvas);
155 timings.push_back(std::move(current_timings));
156 now = base::TimeTicks::Now();
157 }
158 return timings;
159 }
160
SnapshotCommandLog() const161 std::unique_ptr<JSONArray> PictureSnapshot::SnapshotCommandLog() const {
162 LoggingCanvas canvas;
163 picture_->playback(&canvas);
164 return canvas.Log();
165 }
166
167 } // namespace blink
168