static void TestSubstitute(skiatest::Reporter* reporter) { SkAutoTUnref<SkPDFTestDict> proxy(new SkPDFTestDict()); SkAutoTUnref<SkPDFTestDict> stub(new SkPDFTestDict()); SkAutoTUnref<SkPDFInt> int33(new SkPDFInt(33)); SkAutoTUnref<SkPDFDict> stubResource(new SkPDFDict()); SkAutoTUnref<SkPDFInt> int44(new SkPDFInt(44)); stub->insert("Value", int33.get()); stubResource->insert("InnerValue", int44.get()); stub->addResource(stubResource.get()); SkPDFCatalog catalog((SkPDFDocument::Flags)0); catalog.addObject(proxy.get(), false); catalog.setSubstitute(proxy.get(), stub.get()); SkDynamicMemoryWStream buffer; proxy->emit(&buffer, &catalog, false); catalog.emitSubstituteResources(&buffer, false); char objectResult[] = "2 0 obj\n<</Value 33\n>>\nendobj\n"; REPORTER_ASSERT( reporter, catalog.setFileOffset(proxy.get(), 0) == strlen(objectResult)); char expectedResult[] = "<</Value 33\n>>1 0 obj\n<</InnerValue 44\n>>\nendobj\n"; REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult)); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult, buffer.getOffset())); }
static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream, size_t dataSize) { if (testStream == NULL) return; SkMemoryStream testData(dataSize); uint8_t* data = (uint8_t*)testData.getMemoryBase(); srand(0); // Make data deterministic. for (size_t i = 0; i < dataSize; i++) data[i] = rand() & 0xFF; testStream->setMemory(testData.getMemoryBase(), dataSize, true); SkDynamicMemoryWStream compressed; bool status = SkFlate::Deflate(testStream, &compressed); REPORTER_ASSERT(reporter, status); // Check that the input data wasn't changed. size_t inputSize = testStream->getLength(); if (inputSize == 0) inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey); REPORTER_ASSERT(reporter, testData.getLength() == inputSize); REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(), testStream->getMemoryBase(), testData.getLength()) == 0); // Assume there are two test sizes, big and small. if (dataSize < 1024) REPORTER_ASSERT(reporter, compressed.getOffset() < 1024); else REPORTER_ASSERT(reporter, compressed.getOffset() > 1024); SkAutoDataUnref data1(compressed.copyToData()); testStream->setData(data1.get())->unref(); SkDynamicMemoryWStream uncompressed; status = SkFlate::Inflate(testStream, &uncompressed); REPORTER_ASSERT(reporter, status); // Check that the input data wasn't changed. inputSize = testStream->getLength(); if (inputSize == 0) inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey); REPORTER_ASSERT(reporter, data1->size() == inputSize); REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(), data1->data(), data1->size()) == 0); // Check that the uncompressed data matches the source data. SkAutoDataUnref data2(uncompressed.copyToData()); REPORTER_ASSERT(reporter, testData.getLength() == uncompressed.getOffset()); REPORTER_ASSERT(reporter, memcmp(testData.getMemoryBase(), data2->data(), testData.getLength()) == 0); }
void SkParsePath::ToSVGString(const SkPath& path, SkString* str) { SkDynamicMemoryWStream stream; SkPath::Iter iter(path, false); SkPoint pts[4]; for (;;) { switch (iter.next(pts, false)) { case SkPath::kMove_Verb: append_scalars(&stream, 'M', &pts[0].fX, 2); break; case SkPath::kLine_Verb: append_scalars(&stream, 'L', &pts[1].fX, 2); break; case SkPath::kQuad_Verb: append_scalars(&stream, 'Q', &pts[1].fX, 4); break; case SkPath::kCubic_Verb: append_scalars(&stream, 'C', &pts[1].fX, 6); break; case SkPath::kClose_Verb: stream.write("Z", 1); break; case SkPath::kDone_Verb: str->resize(stream.getOffset()); stream.copyTo(str->writable_str()); return; } } }
static void TestWStream(skiatest::Reporter* reporter) { SkDynamicMemoryWStream ds; const char s[] = "abcdefghijklmnopqrstuvwxyz"; int i; for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); char* dst = new char[100 * 26 + 1]; dst[100*26] = '*'; ds.copyTo(dst); REPORTER_ASSERT(reporter, dst[100*26] == '*'); // char* p = dst; for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); } { SkData* data = ds.copyToData(); REPORTER_ASSERT(reporter, 100 * 26 == data->size()); REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0); data->unref(); } delete[] dst; }
void SkPDFStream::emitObject(SkWStream* stream, const SkPDFObjNumMap& objNumMap, const SkPDFSubstituteMap& substitutes) { if (fState == kUnused_State) { fState = kNoCompression_State; SkDynamicMemoryWStream compressedData; SkAssertResult( SkFlate::Deflate(fDataStream.get(), &compressedData)); SkAssertResult(fDataStream->rewind()); if (compressedData.getOffset() < this->dataSize()) { SkAutoTDelete<SkStream> compressed( compressedData.detachAsStream()); this->setData(compressed.get()); this->insertName("Filter", "FlateDecode"); } fState = kCompressed_State; this->insertInt("Length", this->dataSize()); } this->INHERITED::emitObject(stream, objNumMap, substitutes); stream->writeText(" stream\n"); stream->writeStream(fDataStream.get(), fDataStream->getLength()); SkAssertResult(fDataStream->rewind()); stream->writeText("\nendstream"); }
static void TestObjectRef(skiatest::Reporter* reporter) { SkAutoTUnref<SkPDFInt> int1(new SkPDFInt(1)); SkAutoTUnref<SkPDFInt> int2(new SkPDFInt(2)); SkAutoTUnref<SkPDFObjRef> int2ref(new SkPDFObjRef(int2.get())); SkPDFCatalog catalog((SkPDFDocument::Flags)0); catalog.addObject(int1.get(), false); catalog.addObject(int2.get(), false); REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int1.get()) == 3); REPORTER_ASSERT(reporter, catalog.getObjectNumberSize(int2.get()) == 3); char expectedResult[] = "2 0 R"; SkDynamicMemoryWStream buffer; int2ref->emitObject(&buffer, &catalog, false); REPORTER_ASSERT(reporter, buffer.getOffset() == strlen(expectedResult)); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedResult, buffer.getOffset())); }
static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { SkASSERT(typeface); SkDynamicMemoryWStream stream; typeface->serialize(&stream); size_t size = stream.getOffset(); if (writer) { writer->write32(size); SkAutoDataUnref data(stream.copyToData()); writer->writePad(data->data(), size); } return 4 + SkAlign4(size); }
static void CheckObjectOutput(skiatest::Reporter* reporter, SkPDFObject* obj, const char* expectedData, size_t expectedSize, bool indirect, bool compression) { SkPDFDocument::Flags docFlags = (SkPDFDocument::Flags) 0; if (!compression) { docFlags = SkTBitOr(docFlags, SkPDFDocument::kFavorSpeedOverSize_Flags); } SkPDFCatalog catalog(docFlags); size_t directSize = obj->getOutputSize(&catalog, false); REPORTER_ASSERT(reporter, directSize == expectedSize); SkDynamicMemoryWStream buffer; obj->emit(&buffer, &catalog, false); REPORTER_ASSERT(reporter, directSize == buffer.getOffset()); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, expectedData, directSize)); if (indirect) { // Indirect output. static char header[] = "1 0 obj\n"; static size_t headerLen = strlen(header); static char footer[] = "\nendobj\n"; static size_t footerLen = strlen(footer); catalog.addObject(obj, false); size_t indirectSize = obj->getOutputSize(&catalog, true); REPORTER_ASSERT(reporter, indirectSize == directSize + headerLen + footerLen); buffer.reset(); obj->emit(&buffer, &catalog, true); REPORTER_ASSERT(reporter, indirectSize == buffer.getOffset()); REPORTER_ASSERT(reporter, stream_equals(buffer, 0, header, headerLen)); REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen, expectedData, directSize)); REPORTER_ASSERT(reporter, stream_equals(buffer, headerLen + directSize, footer, footerLen)); } }
void drawpicture(SkCanvas* canvas, SkPicture& pict) { #if 0 SkDynamicMemoryWStream ostream; pict.serialize(&ostream); SkMemoryStream istream(ostream.getStream(), ostream.getOffset()); SkPicture* newPict = new SkPicture(&istream); canvas->drawPicture(*newPict); newPict->unref(); #else canvas->drawPicture(pict); #endif }
void SampleWindow::afterChildren(SkCanvas* orig) { switch (fCanvasType) { case kRaster_CanvasType: break; case kPicture_CanvasType: if (true) { SkPicture* pict = new SkPicture(*fPicture); fPicture->unref(); orig->drawPicture(*pict); pict->unref(); } else if (true) { SkDynamicMemoryWStream ostream; fPicture->serialize(&ostream); fPicture->unref(); SkMemoryStream istream(ostream.getStream(), ostream.getOffset()); SkPicture pict(&istream); orig->drawPicture(pict); } else { fPicture->draw(orig); fPicture->unref(); } fPicture = NULL; break; #ifdef SK_SUPPORT_GL case kOpenGL_CanvasType: glFlush(); delete fGLCanvas; fGLCanvas = NULL; #ifdef USE_OFFSCREEN reverseRedAndBlue(orig->getDevice()->accessBitmap(true)); #endif break; #endif } // if ((fScrollTestX | fScrollTestY) != 0) { const SkBitmap& bm = orig->getDevice()->accessBitmap(true); int dx = fScrollTestX * 7; int dy = fScrollTestY * 7; SkIRect r; SkRegion inval; r.set(50, 50, 50+100, 50+100); bm.scrollRect(&r, dx, dy, &inval); paint_rgn(bm, r, inval); } }
void SkOrderedWriteBuffer::writeBitmap(const SkBitmap& bitmap) { bool encoded = false; if (fBitmapEncoder != NULL) { SkDynamicMemoryWStream pngStream; if (fBitmapEncoder(&pngStream, bitmap)) { encoded = true; if (encoded) { uint32_t offset = fWriter.bytesWritten(); // Write the length to indicate that the bitmap was encoded successfully. size_t length = pngStream.getOffset(); this->writeUInt(length); // Now write the stream. if (pngStream.read(fWriter.reservePad(length), 0, length)) { // Write the width and height in case the reader does not have a decoder. this->writeInt(bitmap.width()); this->writeInt(bitmap.height()); } else { // Writing the stream failed, so go back to original state to store another way. fWriter.rewindToOffset(offset); encoded = false; } } } } if (!encoded) { // Bitmap was not encoded. Record a zero, implying that the reader need not decode. this->writeUInt(0); if (fBitmapHeap) { int32_t slot = fBitmapHeap->insert(bitmap); fWriter.write32(slot); // crbug.com/155875 // The generation ID is not required information. We write it to prevent collisions // in SkFlatDictionary. It is possible to get a collision when a previously // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary // and the instance currently being written is re-using the same slot from the // bitmap heap. fWriter.write32(bitmap.getGenerationID()); } else { bitmap.flatten(*this); } } }
extern "C" int JpegStub_compress(JpegStub* stub, const void* image, int width, int height, int quality) { void* pY = const_cast<void*>(image); int offsets[2]; offsets[0] = 0; offsets[1] = width * height; Yuv420SpToJpegEncoder* encoder = (Yuv420SpToJpegEncoder*)stub->mInternalEncoder; SkDynamicMemoryWStream* stream = (SkDynamicMemoryWStream*)stub->mInternalStream; if (encoder->encode(stream, pY, width, height, offsets, quality)) { ALOGV("%s: Compressed JPEG: %d[%dx%d] -> %d bytes", __FUNCTION__, (width * height * 12) / 8, width, height, stream->getOffset()); return 0; } else { ALOGE("%s: JPEG compression failed", __FUNCTION__); return errno ? errno: EINVAL; } }
void SkParsePath::ToSVGString(const SkPath& path, SkString* str) { SkDynamicMemoryWStream stream; SkPath::Iter iter(path, false); SkPoint pts[4]; for (;;) { switch (iter.next(pts, false)) { case SkPath::kConic_Verb: { const SkScalar tol = SK_Scalar1 / 1024; // how close to a quad SkAutoConicToQuads quadder; const SkPoint* quadPts = quadder.computeQuads(pts, iter.conicWeight(), tol); for (int i = 0; i < quadder.countQuads(); ++i) { append_scalars(&stream, 'Q', &quadPts[i*2 + 1].fX, 4); } } break; case SkPath::kMove_Verb: append_scalars(&stream, 'M', &pts[0].fX, 2); break; case SkPath::kLine_Verb: append_scalars(&stream, 'L', &pts[1].fX, 2); break; case SkPath::kQuad_Verb: append_scalars(&stream, 'Q', &pts[1].fX, 4); break; case SkPath::kCubic_Verb: append_scalars(&stream, 'C', &pts[1].fX, 6); break; case SkPath::kClose_Verb: stream.write("Z", 1); break; case SkPath::kDone_Verb: str->resize(stream.getOffset()); stream.copyTo(str->writable_str()); return; } } }
String ImageBuffer::toDataURL(const String&, const double*) const { ASSERT(context() && context()->platformContext()); // Request for canvas bitmap; conversion required. if (context()->platformContext()->isRecording()) context()->platformContext()->convertToNonRecording(); // Encode the image into a vector. SkDynamicMemoryWStream pngStream; const SkBitmap& dst = android_gc2canvas(context())->getDevice()->accessBitmap(true); SkImageEncoder::EncodeStream(&pngStream, dst, SkImageEncoder::kPNG_Type, 100); // Convert it into base64. Vector<char> pngEncodedData; pngEncodedData.append(pngStream.getStream(), pngStream.getOffset()); Vector<char> base64EncodedData; base64Encode(pngEncodedData, base64EncodedData); // Append with a \0 so that it's a valid string. base64EncodedData.append('\0'); // And the resulting string. return String::format("data:image/png;base64,%s", base64EncodedData.data()); }
bool SkPDFStream::populate(SkPDFCatalog* catalog) { #ifdef SK_NO_FLATE if (fState == kUnused_State) { fState = kNoCompression_State; insertInt("Length", this->dataSize()); } return true; #else // !SK_NO_FLATE if (fState == kUnused_State) { fState = kNoCompression_State; SkDynamicMemoryWStream compressedData; SkAssertResult( SkFlate::Deflate(fDataStream.get(), &compressedData)); SkAssertResult(fDataStream->rewind()); if (compressedData.getOffset() < this->dataSize()) { SkAutoTDelete<SkStream> compressed( compressedData.detachAsStream()); this->setData(compressed.get()); insertName("Filter", "FlateDecode"); } fState = kCompressed_State; insertInt("Length", this->dataSize()); } else if (fState == kNoCompression_State) { if (!fSubstitute.get()) { fSubstitute.reset(new SkPDFStream(*this)); catalog->setSubstitute(this, fSubstitute.get()); } return false; } return true; #endif // SK_NO_FLATE }
size_t SkPDFDocument::headerSize() { SkDynamicMemoryWStream buffer; emitHeader(&buffer); return buffer.getOffset(); }
static void TestWStream(skiatest::Reporter* reporter) { SkDynamicMemoryWStream ds; const char s[] = "abcdefghijklmnopqrstuvwxyz"; int i; for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); char* dst = new char[100 * 26 + 1]; dst[100*26] = '*'; ds.copyTo(dst); REPORTER_ASSERT(reporter, dst[100*26] == '*'); for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); } { SkAutoTDelete<SkStreamAsset> stream(ds.detachAsStream()); REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); REPORTER_ASSERT(reporter, ds.getOffset() == 0); test_loop_stream(reporter, stream.get(), s, 26, 100); SkAutoTDelete<SkStreamAsset> stream2(stream->duplicate()); test_loop_stream(reporter, stream2.get(), s, 26, 100); SkAutoTDelete<SkStreamAsset> stream3(stream->fork()); REPORTER_ASSERT(reporter, stream3->isAtEnd()); char tmp; size_t bytes = stream->read(&tmp, 1); REPORTER_ASSERT(reporter, 0 == bytes); stream3->rewind(); test_loop_stream(reporter, stream3.get(), s, 26, 100); } for (i = 0; i < 100; i++) { REPORTER_ASSERT(reporter, ds.write(s, 26)); } REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); { SkAutoTUnref<SkData> data(ds.copyToData()); REPORTER_ASSERT(reporter, 100 * 26 == data->size()); REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0); } { // Test that this works after a copyToData. SkAutoTDelete<SkStreamAsset> stream(ds.detachAsStream()); REPORTER_ASSERT(reporter, ds.getOffset() == 0); test_loop_stream(reporter, stream.get(), s, 26, 100); SkAutoTDelete<SkStreamAsset> stream2(stream->duplicate()); test_loop_stream(reporter, stream2.get(), s, 26, 100); } delete[] dst; SkString tmpDir = skiatest::GetTmpDir(); if (!tmpDir.isEmpty()) { test_filestreams(reporter, tmpDir.c_str()); } }
int main(int argc, char** argv) { const char* pname = argv[0]; bool png = false; int c; while ((c = getopt(argc, argv, "ph")) != -1) { switch (c) { case 'p': png = true; break; case '?': case 'h': usage(pname); return 1; } } argc -= optind; argv += optind; int fd = -1; if (argc == 0) { fd = dup(STDOUT_FILENO); } else if (argc == 1) { const char* fn = argv[0]; fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664); if (fd == -1) { fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno)); return 1; } const int len = strlen(fn); if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) { png = true; } } if (fd == -1) { usage(pname); return 1; } void const* mapbase = MAP_FAILED; ssize_t mapsize = -1; void const* base = 0; uint32_t w, h, f; size_t size = 0; ScreenshotClient screenshot; if (screenshot.update() == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { const char* fbpath = "/dev/graphics/fb0"; int fb = open(fbpath, O_RDONLY); if (fb >= 0) { struct fb_var_screeninfo vinfo; if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) { uint32_t bytespp; if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) { size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); if (mapbase != MAP_FAILED) { base = (void const *)((char const *)mapbase + offset); } } } close(fb); } } if (base) { if (png) { SkBitmap b; b.setConfig(flinger2skia(f), w, h); b.setPixels((void*)base); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); write(fd, stream.getStream(), stream.getOffset()); } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); write(fd, base, size); } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; }
static void TestFlate(skiatest::Reporter* reporter, SkMemoryStream* testStream, size_t dataSize) { SkASSERT(testStream != NULL); SkAutoDataUnref testData(new_test_data(dataSize)); SkASSERT(testData->size() == dataSize); testStream->setMemory(testData->data(), dataSize, /*copyData=*/ true); SkDynamicMemoryWStream compressed; bool deflateSuccess = SkFlate::Deflate(testStream, &compressed); REPORTER_ASSERT(reporter, deflateSuccess); // Check that the input data wasn't changed. size_t inputSize = testStream->getLength(); if (inputSize == 0) { inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey); } REPORTER_ASSERT(reporter, dataSize == inputSize); if (dataSize == inputSize) { REPORTER_ASSERT(reporter, memcmp(testData->data(), testStream->getMemoryBase(), dataSize) == 0); } size_t compressedSize = compressed.getOffset(); SkAutoDataUnref compressedData(compressed.copyToData()); testStream->setData(compressedData.get()); SkDynamicMemoryWStream uncompressed; bool inflateSuccess = SkFlate::Inflate(testStream, &uncompressed); REPORTER_ASSERT(reporter, inflateSuccess); // Check that the input data wasn't changed. inputSize = testStream->getLength(); if (inputSize == 0) { inputSize = testStream->read(NULL, SkZeroSizeMemStream::kGetSizeKey); } REPORTER_ASSERT(reporter, compressedSize == inputSize); if (compressedData->size() == inputSize) { REPORTER_ASSERT(reporter, memcmp(testStream->getMemoryBase(), compressedData->data(), compressedData->size()) == 0); } // Check that the uncompressed data matches the source data. SkAutoDataUnref uncompressedData(uncompressed.copyToData()); REPORTER_ASSERT(reporter, dataSize == uncompressedData->size()); if (dataSize == uncompressedData->size()) { REPORTER_ASSERT(reporter, memcmp(testData->data(), uncompressedData->data(), dataSize) == 0); } if (compressedSize < 1) { return; } double compressionRatio = static_cast<double>(dataSize) / compressedSize; // Assert that some compression took place. REPORTER_ASSERT(reporter, compressionRatio > 1.2); if (reporter->verbose()) { SkDebugf("Flate Test: \t input size: " SK_SIZE_T_SPECIFIER "\tcompressed size: " SK_SIZE_T_SPECIFIER "\tratio: %.4g\n", dataSize, compressedSize, compressionRatio); } }
size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { SkDynamicMemoryWStream buffer; emit(&buffer, catalog, indirect); return buffer.getOffset(); }
size_t SkPDFCatalog::getObjectNumberSize(SkPDFObject* obj) { SkDynamicMemoryWStream buffer; emitObjectNumber(&buffer, obj); return buffer.getOffset(); }
extern "C" size_t JpegStub_getCompressedSize(JpegStub* stub) { SkDynamicMemoryWStream* stream = (SkDynamicMemoryWStream*)stub->mInternalStream; return stream->getOffset(); }