1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2012 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkWriteBuffer.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBitmap.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkData.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDeduper.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPaint.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPixelRef.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPtrRecorder.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkStream.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypeface.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////////////
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkBinaryWriteBuffer::SkBinaryWriteBuffer()
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fFactorySet(nullptr)
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fTFSet(nullptr) {
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkBinaryWriteBuffer::SkBinaryWriteBuffer(void* storage, size_t storageSize)
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    : fFactorySet(nullptr)
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fWriter(storage, storageSize)
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    , fTFSet(nullptr) {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkBinaryWriteBuffer::~SkBinaryWriteBuffer() {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkSafeUnref(fFactorySet);
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkSafeUnref(fTFSet);
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeByteArray(const void* data, size_t size) {
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(SkToU32(size));
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writePad(data, size);
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeBool(bool value) {
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeBool(value);
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeScalar(SkScalar value) {
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeScalar(value);
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeScalarArray(const SkScalar* value, uint32_t count) {
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(count);
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(value, count * sizeof(SkScalar));
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeInt(int32_t value) {
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(value);
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeIntArray(const int32_t* value, uint32_t count) {
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(count);
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(value, count * sizeof(int32_t));
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeUInt(uint32_t value) {
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(value);
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeString(const char* value) {
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeString(value);
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeColor(SkColor color) {
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(color);
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeColorArray(const SkColor* color, uint32_t count) {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(count);
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(color, count * sizeof(SkColor));
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeColor4f(const SkColor4f& color) {
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(&color, sizeof(SkColor4f));
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeColor4fArray(const SkColor4f* color, uint32_t count) {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(count);
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(color, count * sizeof(SkColor4f));
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writePoint(const SkPoint& point) {
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeScalar(point.fX);
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeScalar(point.fY);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writePointArray(const SkPoint* point, uint32_t count) {
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(count);
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(point, count * sizeof(SkPoint));
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeMatrix(const SkMatrix& matrix) {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeMatrix(matrix);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeIRect(const SkIRect& rect) {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write(&rect, sizeof(SkIRect));
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeRect(const SkRect& rect) {
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeRect(rect);
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeRegion(const SkRegion& region) {
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writeRegion(region);
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writePath(const SkPath& path) {
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.writePath(path);
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t SkBinaryWriteBuffer::writeStream(SkStream* stream, size_t length) {
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(SkToU32(length));
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t bytesWritten = fWriter.readFromStream(stream, length);
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (bytesWritten < length) {
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fWriter.reservePad(length - bytesWritten);
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return bytesWritten;
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkBinaryWriteBuffer::writeToStream(SkWStream* stream) {
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return fWriter.writeToStream(stream);
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeImage(const SkImage* image) {
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDeduper) {
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->write32(fDeduper->findOrDefineImage(const_cast<SkImage*>(image)));
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->writeInt(image->width());
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->writeInt(image->height());
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto write_data = [this](sk_sp<SkData> data, int sign) {
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        size_t size = data ? data->size() : 0;
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!sk_64_isS32(size)) {
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size = 0;   // too big to store
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (size) {
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->write32(SkToS32(size) * sign);
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->writePad32(data->data(), size);    // does nothing if size == 0
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->write32(0);   // origin-x
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->write32(0);   // origin-y
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->write32(0);   // signal no image
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    /*
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *  What follows is a 32bit encoded size.
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *   0 : failure, nothing else to do
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *  <0 : negative (int32_t) of a custom encoded blob using SerialProcs
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     *  >0 : standard encoded blob size (use MakeFromEncoded)
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot     */
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkData> data;
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int sign = 1;   // +1 signals standard encoder
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fProcs.fImageProc) {
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        data = fProcs.fImageProc(const_cast<SkImage*>(image), fProcs.fImageCtx);
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sign = -1;  // +1 signals custom encoder
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // We check data, since a custom proc can return nullptr, in which case we behave as if
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // there was no custom proc.
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!data) {
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        data = image->encodeToData();
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sign = 1;
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    write_data(std::move(data), sign);
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) {
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDeduper) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->write32(fDeduper->findOrDefineTypeface(obj));
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Write 32 bits (signed)
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //   0 -- default font
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //  >0 -- index
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //  <0 -- custom (serial procs)
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (obj == nullptr) {
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fWriter.write32(0);
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else if (fProcs.fTypefaceProc) {
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        auto data = fProcs.fTypefaceProc(obj, fProcs.fTypefaceCtx);
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (data) {
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            size_t size = data->size();
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (!sk_64_isS32(size)) {
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                size = 0;               // fall back to default font
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int32_t ssize = SkToS32(size);
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            fWriter.write32(-ssize);    // negative to signal custom
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (size) {
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->writePad32(data->data(), size);
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // no data means fall through for std behavior
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.write32(fTFSet ? fTFSet->add(obj) : 0);
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writePaint(const SkPaint& paint) {
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    paint.flatten(*this);
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkFactorySet* SkBinaryWriteBuffer::setFactoryRecorder(SkFactorySet* rec) {
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRefCnt_SafeAssign(fFactorySet, rec);
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return rec;
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkRefCntSet* SkBinaryWriteBuffer::setTypefaceRecorder(SkRefCntSet* rec) {
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRefCnt_SafeAssign(fTFSet, rec);
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return rec;
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) {
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == flattenable) {
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->write32(0);
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fDeduper) {
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->write32(fDeduper->findOrDefineFactory(const_cast<SkFlattenable*>(flattenable)));
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        /*
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *  We can write 1 of 2 versions of the flattenable:
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *  1.  index into fFactorySet : This assumes the writer will later
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      resolve the function-ptrs into strings for its reader. SkPicture
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      does exactly this, by writing a table of names (matching the indices)
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      up front in its serialized form.
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *  2.  string name of the flattenable or index into fFlattenableDict:  We
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      store the string to allow the reader to specify its own factories
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      after write time.  In order to improve compression, if we have
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         *      already written the string, we write its index instead.
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot         */
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (fFactorySet) {
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkFlattenable::Factory factory = flattenable->getFactory();
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(factory);
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            this->write32(fFactorySet->add(factory));
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        } else {
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const char* name = flattenable->getTypeName();
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkASSERT(name);
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkString key(name);
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (uint32_t* indexPtr = fFlattenableDict.find(key)) {
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // We will write the index as a 32-bit int.  We want the first byte
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // that we send to be zero - this will act as a sentinel that we
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // have an index (not a string).  This means that we will send the
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // the index shifted left by 8.  The remaining 24-bits should be
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // plenty to store the index.  Note that this strategy depends on
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // being little endian.
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(0 == *indexPtr >> 24);
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->write32(*indexPtr << 8);
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Otherwise write the string.  Clients should not use the empty
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // string as a name, or we will have a problem.
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkASSERT(strcmp("", name));
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                this->writeString(name);
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                // Add key to dictionary.
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                fFlattenableDict.set(key, fFlattenableDict.count() + 1);
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // make room for the size of the flattened object
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    (void)fWriter.reserve(sizeof(uint32_t));
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // record the current size, so we can subtract after the object writes.
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t offset = fWriter.bytesWritten();
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // now flatten the object
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    flattenable->flatten(*this);
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    size_t objSize = fWriter.bytesWritten() - offset;
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // record the obj's size
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fWriter.overwriteTAt(offset - sizeof(uint32_t), SkToU32(objSize));
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
282