1 /*
2  * Copyright 2015 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 <cstdio>
9 #include <cstdlib>
10 #include <sstream>
11 #include <string>
12 
13 #include "fiddle_main.h"
14 
15 // Globals externed in fiddle_main.h
16 SkBitmap source;
17 sk_sp<SkImage> image;
18 
19 // Global used by the local impl of SkDebugf.
20 std::ostringstream gTextOutput;
21 
SkDebugf(const char * fmt,...)22 void SkDebugf(const char * fmt, ...) {
23     va_list args;
24     va_start(args, fmt);
25     char formatbuffer[1024];
26     int n = vsnprintf(formatbuffer, sizeof(formatbuffer), fmt, args);
27     va_end(args);
28     if (n>=0 && n<=int(sizeof(formatbuffer))) {
29         gTextOutput.write(formatbuffer, n);
30     }
31 }
32 
encode_to_base64(const void * data,size_t size,FILE * out)33 static void encode_to_base64(const void* data, size_t size, FILE* out) {
34     const uint8_t* input = reinterpret_cast<const uint8_t*>(data);
35     const uint8_t* end = &input[size];
36     static const char codes[] =
37             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
38             "abcdefghijklmnopqrstuvwxyz0123456789+/";
39     while (input != end) {
40         uint8_t b = (*input & 0xFC) >> 2;
41         fputc(codes[b], out);
42         b = (*input & 0x03) << 4;
43         ++input;
44         if (input == end) {
45             fputc(codes[b], out);
46             fputs("==", out);
47             return;
48         }
49         b |= (*input & 0xF0) >> 4;
50         fputc(codes[b], out);
51         b = (*input & 0x0F) << 2;
52         ++input;
53         if (input == end) {
54             fputc(codes[b], out);
55             fputc('=', out);
56             return;
57         }
58         b |= (*input & 0xC0) >> 6;
59         fputc(codes[b], out);
60         b = *input & 0x3F;
61         fputc(codes[b], out);
62         ++input;
63     }
64 }
65 
66 
dump_output(const void * data,size_t size,const char * name,bool last=true)67 static void dump_output(const void* data, size_t size,
68                         const char* name, bool last = true) {
69     printf("\t\"%s\": \"", name);
70     encode_to_base64(data, size, stdout);
71     fputs(last ? "\"\n" : "\",\n", stdout);
72 }
73 
dump_output(const sk_sp<SkData> & data,const char * name,bool last=true)74 static void dump_output(const sk_sp<SkData>& data,
75                         const char* name, bool last = true) {
76     if (data) {
77         dump_output(data->data(), data->size(), name, last);
78     }
79 }
80 
encode_snapshot(const sk_sp<SkSurface> & surface)81 static SkData* encode_snapshot(const sk_sp<SkSurface>& surface) {
82     sk_sp<SkImage> img(surface->makeImageSnapshot());
83     return img ? img->encode() : nullptr;
84 }
85 
86 #if defined(__linux) && !defined(__ANDROID__)
87     #include <GL/osmesa.h>
create_grcontext()88     static sk_sp<GrContext> create_grcontext() {
89         // We just leak the OSMesaContext... the process will die soon anyway.
90         if (OSMesaContext osMesaContext = OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, nullptr)) {
91             static uint32_t buffer[16 * 16];
92             OSMesaMakeCurrent(osMesaContext, &buffer, GL_UNSIGNED_BYTE, 16, 16);
93         }
94 
95         auto osmesa_get = [](void* ctx, const char name[]) {
96             SkASSERT(nullptr == ctx);
97             SkASSERT(OSMesaGetCurrentContext());
98             return OSMesaGetProcAddress(name);
99         };
100         sk_sp<const GrGLInterface> mesa(GrGLAssembleInterface(nullptr, osmesa_get));
101         if (!mesa) {
102             return nullptr;
103         }
104         return sk_sp<GrContext>(GrContext::Create(
105                                         kOpenGL_GrBackend,
106                                         reinterpret_cast<intptr_t>(mesa.get())));
107     }
108 #else
create_grcontext()109     static sk_sp<GrContext> create_grcontext() { return nullptr; }
110 #endif
111 
112 
113 
main()114 int main() {
115     DrawOptions options = GetDrawOptions();
116     // If textOnly then only do one type of image, otherwise the text
117     // output is duplicated for each type.
118     if (options.textOnly) {
119         options.raster = true;
120         options.gpu = false;
121         options.pdf = false;
122         options.skp = false;
123     }
124     if (options.source) {
125         sk_sp<SkData> data(SkData::MakeFromFileName(options.source));
126         if (!data) {
127             perror(options.source);
128             return 1;
129         } else {
130             image = SkImage::MakeFromEncoded(std::move(data));
131             if (!image) {
132                 perror("Unable to decode the source image.");
133                 return 1;
134             }
135             SkAssertResult(image->asLegacyBitmap(
136                                    &source, SkImage::kRO_LegacyBitmapMode));
137         }
138     }
139     sk_sp<SkData> rasterData, gpuData, pdfData, skpData;
140     SkColorType colorType = kN32_SkColorType;
141     sk_sp<SkColorSpace> colorSpace = nullptr;
142     if (options.f16) {
143         SkASSERT(options.srgb);
144         colorType = kRGBA_F16_SkColorType;
145         colorSpace = SkColorSpace::MakeSRGBLinear();
146     } else if (options.srgb) {
147         colorSpace = SkColorSpace::MakeSRGB();
148     }
149     SkImageInfo info = SkImageInfo::Make(options.size.width(), options.size.height(), colorType,
150                                          kPremul_SkAlphaType, colorSpace);
151     if (options.raster) {
152         auto rasterSurface = SkSurface::MakeRaster(info);
153         srand(0);
154         draw(rasterSurface->getCanvas());
155         rasterData.reset(encode_snapshot(rasterSurface));
156     }
157     if (options.gpu) {
158         auto grContext = create_grcontext();
159         if (!grContext) {
160             fputs("Unable to get GrContext.\n", stderr);
161         } else {
162             auto surface = SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kNo, info);
163             if (!surface) {
164                 fputs("Unable to get render surface.\n", stderr);
165                 exit(1);
166             }
167             srand(0);
168             draw(surface->getCanvas());
169             gpuData.reset(encode_snapshot(surface));
170         }
171     }
172     if (options.pdf) {
173         SkDynamicMemoryWStream pdfStream;
174         sk_sp<SkDocument> document(SkDocument::MakePDF(&pdfStream));
175         if (document) {
176             srand(0);
177             draw(document->beginPage(options.size.width(), options.size.height()));
178             document->close();
179             pdfData = pdfStream.detachAsData();
180         }
181     }
182     if (options.skp) {
183         SkSize size;
184         size = options.size;
185         SkPictureRecorder recorder;
186         srand(0);
187         draw(recorder.beginRecording(size.width(), size.height()));
188         auto picture = recorder.finishRecordingAsPicture();
189         SkDynamicMemoryWStream skpStream;
190         picture->serialize(&skpStream);
191         skpData = skpStream.detachAsData();
192     }
193 
194     printf("{\n");
195     if (!options.textOnly) {
196         dump_output(rasterData, "Raster", !gpuData && !pdfData && !skpData);
197         dump_output(gpuData, "Gpu", !pdfData && !skpData);
198         dump_output(pdfData, "Pdf", !skpData);
199         dump_output(skpData, "Skp");
200     } else {
201         std::string textoutput = gTextOutput.str();
202         dump_output(textoutput.c_str(), textoutput.length(), "Text");
203     }
204     printf("}\n");
205 
206     return 0;
207 }
208