static bool SK_WARN_UNUSED_RESULT flatten(const SkImage& image, Json::Value* target, bool sendBinaries) { if (sendBinaries) { SkData* encoded = image.encode(SkImageEncoder::kPNG_Type, 100); if (encoded == nullptr) { // PNG encode doesn't necessarily support all color formats, convert to a different // format size_t rowBytes = 4 * image.width(); void* buffer = sk_malloc_throw(rowBytes * image.height()); SkImageInfo dstInfo = SkImageInfo::Make(image.width(), image.height(), kN32_SkColorType, kPremul_SkAlphaType); if (!image.readPixels(dstInfo, buffer, rowBytes, 0, 0)) { SkDebugf("readPixels failed\n"); return false; } SkImage* converted = SkImage::NewRasterCopy(dstInfo, buffer, rowBytes); encoded = converted->encode(SkImageEncoder::kPNG_Type, 100); if (encoded == nullptr) { SkDebugf("image encode failed\n"); return false; } free(converted); free(buffer); } Json::Value bytes; encode_data(encoded->data(), encoded->size(), &bytes); (*target)[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes; encoded->unref(); } else { SkString description = SkStringPrintf("%dx%d pixel image", image.width(), image.height()); (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(description.c_str()); } return true; }
void TestDataRef(skiatest::Reporter* reporter) { const char* str = "We the people, in order to form a more perfect union."; const int N = 10; SkData* r0 = SkData::NewEmpty(); SkData* r1 = SkData::NewWithCopy(str, strlen(str)); SkData* r2 = SkData::NewWithProc(new int[N], N*sizeof(int), delete_int_proc, gGlobal); SkData* r3 = SkData::NewSubset(r1, 7, 6); SkAutoUnref aur0(r0); SkAutoUnref aur1(r1); SkAutoUnref aur2(r2); SkAutoUnref aur3(r3); assert_len(reporter, r0, 0); assert_len(reporter, r1, strlen(str)); assert_len(reporter, r2, N * sizeof(int)); assert_len(reporter, r3, 6); assert_data(reporter, r1, str, strlen(str)); assert_data(reporter, r3, "people", 6); SkData* tmp = SkData::NewSubset(r1, strlen(str), 10); assert_len(reporter, tmp, 0); tmp->unref(); tmp = SkData::NewSubset(r1, 0, 0); assert_len(reporter, tmp, 0); tmp->unref(); }
DEF_TEST(Data, reporter) { const char* str = "We the people, in order to form a more perfect union."; const int N = 10; SkAutoTUnref<SkData> r0(SkData::NewEmpty()); SkAutoTUnref<SkData> r1(SkData::NewWithCopy(str, strlen(str))); SkAutoTUnref<SkData> r2(SkData::NewWithProc(new int[N], N*sizeof(int), delete_int_proc, gGlobal)); SkAutoTUnref<SkData> r3(SkData::NewSubset(r1, 7, 6)); assert_len(reporter, r0, 0); assert_len(reporter, r1, strlen(str)); assert_len(reporter, r2, N * sizeof(int)); assert_len(reporter, r3, 6); assert_data(reporter, r1, str, strlen(str)); assert_data(reporter, r3, "people", 6); SkData* tmp = SkData::NewSubset(r1, strlen(str), 10); assert_len(reporter, tmp, 0); tmp->unref(); tmp = SkData::NewSubset(r1, 0, 0); assert_len(reporter, tmp, 0); tmp->unref(); test_cstring(reporter); test_files(reporter); }
int tool_main(int argc, char** argv) { SkAutoGraphics ag; SkLua L; for (int i = 1; i < argc; ++i) { SkData* data = nullptr; const void* ptr; size_t len; if (!strcmp(argv[i], "--lua") && i < argc-1) { ptr = argv[i + 1]; len = strlen(argv[i + 1]); i += 1; } else { data = read_into_data(argv[i]); ptr = data->data(); len = data->size(); } if (!L.runCode(ptr, len)) { SkDebugf("failed to load %s\n", argv[i]); exit(-1); } SkSafeUnref(data); } return 0; }
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; }
static SkData* make_3Dlut(int* cubeDimension, bool invR, bool invG, bool invB) { int size = 4 << R(5); SkData* data = SkData::NewUninitialized(sizeof(SkColor) * size * size * size); SkColor* pixels = (SkColor*)(data->writable_data()); SkAutoTMalloc<uint8_t> lutMemory(size); SkAutoTMalloc<uint8_t> invLutMemory(size); uint8_t* lut = lutMemory.get(); uint8_t* invLut = invLutMemory.get(); const int maxIndex = size - 1; for (int i = 0; i < size; i++) { lut[i] = (i * 255) / maxIndex; invLut[i] = ((maxIndex - i) * 255) / maxIndex; } for (int r = 0; r < size; ++r) { for (int g = 0; g < size; ++g) { for (int b = 0; b < size; ++b) { pixels[(size * ((size * b) + g)) + r] = SkColorSetARGB(0xFF, invR ? invLut[r] : lut[r], invG ? invLut[g] : lut[g], invB ? invLut[b] : lut[b]); } } } if (cubeDimension) { *cubeDimension = size; } return data; }
static void decodeThreadWithRefEncodedMain(ImageFrameGenerator* generator) { // Image must be complete - refEncodedData otherwise returns null. char buffer[100 * 100 * 4]; SkData* data = generator->refEncodedData(); generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); data->unref(); }
// asserts that inner is a subset of outer static void test_dataset_subset(skiatest::Reporter* reporter, const SkDataSet& outer, const SkDataSet& inner) { SkDataSet::Iter iter(inner); for (; !iter.done(); iter.next()) { SkData* outerData = outer.find(iter.key()); REPORTER_ASSERT(reporter, outerData); REPORTER_ASSERT(reporter, outerData->equals(iter.value())); } }
static void TypefaceStyle_test(skiatest::Reporter* reporter, uint16_t weight, uint16_t width, SkData* data) { sk_sp<SkData> dataCopy; SkData* dataToUse = data; if (!dataToUse->unique()) { dataCopy = SkData::MakeWithCopy(data->data(), data->size()); dataToUse = dataCopy.get(); } SkSFNTHeader* sfntHeader = static_cast<SkSFNTHeader*>(dataToUse->writable_data()); SkSFNTHeader::TableDirectoryEntry* tableEntry = SkTAfter<SkSFNTHeader::TableDirectoryEntry>(sfntHeader); SkSFNTHeader::TableDirectoryEntry* os2TableEntry = nullptr; int numTables = SkEndian_SwapBE16(sfntHeader->numTables); for (int tableEntryIndex = 0; tableEntryIndex < numTables; ++tableEntryIndex) { if (SkOTTableOS2::TAG == tableEntry[tableEntryIndex].tag) { os2TableEntry = tableEntry + tableEntryIndex; break; } } SkASSERT_RELEASE(os2TableEntry); size_t os2TableOffset = SkEndian_SwapBE32(os2TableEntry->offset); SkOTTableOS2_V0* os2Table = SkTAddOffset<SkOTTableOS2_V0>(sfntHeader, os2TableOffset); os2Table->usWeightClass.value = SkEndian_SwapBE16(weight); using WidthType = SkOTTableOS2_V0::WidthClass::Value; os2Table->usWidthClass.value = static_cast<WidthType>(SkEndian_SwapBE16(width)); sk_sp<SkTypeface> newTypeface(SkTypeface::MakeFromStream(new SkMemoryStream(dataToUse))); SkASSERT_RELEASE(newTypeface); SkFontStyle newStyle = newTypeface->fontStyle(); //printf("%d, %f\n", weight, (newStyle.weight() - (float)0x7FFF) / (float)0x7FFF); //printf("%d, %f\n", width , (newStyle.width() - (float)0x7F) / (float)0x7F); //printf("%d, %d\n", weight, newStyle.weight()); //printf("%d, %d\n", width , newStyle.width()); // Some back-ends (CG, GDI, DW) support OS/2 version A which uses 0 - 10 (but all differently). REPORTER_ASSERT(reporter, newStyle.weight() == weight || (weight <= 10 && newStyle.weight() == 100 * weight) || (weight == 4 && newStyle.weight() == 350) || // GDI weirdness (weight == 5 && newStyle.weight() == 400) || // GDI weirdness (weight == 0 && newStyle.weight() == 1) || // DW weirdness (weight == 1000 && newStyle.weight() == 999) // DW weirdness ); // Some back-ends (GDI) don't support width, ensure these always report 'medium'. REPORTER_ASSERT(reporter, newStyle.width() == width || newStyle.width() == 5); }
SkData* SkData::PrivateNewWithCopy(const void* srcOrNull, size_t length) { if (0 == length) { return SkData::NewEmpty(); } char* storage = (char*)sk_malloc_throw(sizeof(SkData) + length); SkData* data = new (storage) SkData(length); if (srcOrNull) { memcpy(data->writable_data(), srcOrNull, length); } return data; }
DEF_TEST(ImageDataRef, reporter) { SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1); size_t rowBytes = info.minRowBytes(); size_t size = info.getSafeSize(rowBytes); SkData* data = SkData::NewUninitialized(size); REPORTER_ASSERT(reporter, data->unique()); SkImage* image = SkImage::NewRasterData(info, data, rowBytes); REPORTER_ASSERT(reporter, !data->unique()); image->unref(); REPORTER_ASSERT(reporter, data->unique()); data->unref(); }
SkData* SkRecorder::newDrawableSnapshot(SkBBHFactory* factory, uint32_t recordFlags) { const int count = fDrawableList.count(); if (0 == count) { return NULL; } SkData* data = new_uninitialized_refcnt_ptrs(count); SkPicture** pics = reinterpret_cast<SkPicture**>(data->writable_data()); for (int i = 0; i < count; ++i) { pics[i] = fDrawableList[i]->newPictureSnapshot(factory, recordFlags); } return data; }
static void send_picture(int socket, const PictureHeader& header, const SkData& skp) { // Vectored IO lets us send header and skp contiguously without first // copying them to a contiguous buffer. struct nn_iovec iov[] = { create_iov(&header, sizeof(header)), create_iov(skp.data(), skp.size()), }; struct nn_msghdr msg; sk_bzero(&msg, sizeof(msg)); msg.msg_iov = iov; msg.msg_iovlen = SK_ARRAY_COUNT(iov); nn_sendmsg(socket, &msg, 0/*flags*/); }
SkData* CompressBitmapToFormat(const SkPixmap& pixmap, Format format) { int compressedDataSize = GetCompressedDataSize(format, pixmap.width(), pixmap.height()); if (compressedDataSize < 0) { return NULL; } const uint8_t* src = reinterpret_cast<const uint8_t*>(pixmap.addr()); SkData* dst = SkData::NewUninitialized(compressedDataSize); if (!CompressBufferToFormat((uint8_t*)dst->writable_data(), src, pixmap.colorType(), pixmap.width(), pixmap.height(), pixmap.rowBytes(), format)) { dst->unref(); dst = NULL; } return dst; }
lua_State* ensureLua() { if (NULL == fLua) { fLua = SkNEW(SkLua); SkString str = GetResourcePath(LUA_FILENAME); SkData* data = SkData::NewFromFileName(str.c_str()); if (data) { fLua->runCode(data->data(), data->size()); data->unref(); this->setImageFilename(fLua->get()); } else { fLua->runCode(gMissingCode); } } return fLua->get(); }
String ImageBuffer::toDataURL(const String&, const double*) const { // Encode the image into a vector. SkDynamicMemoryWStream pngStream; const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true); SkImageEncoder::EncodeStream(&pngStream, dst, SkImageEncoder::kPNG_Type, 100); // Convert it into base64. Vector<char> pngEncodedData; SkData* streamData = pngStream.copyToData(); pngEncodedData.append((char*)streamData->data(), streamData->size()); streamData->unref(); 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()); }
/* If you execute skp_parser with one argument, it spits out a json representation of the skp, but that's incomplete since it's missing many binary blobs (these could represent images or typefaces or just anything that doesn't currently have a json representation). Each unique blob is labeled with a string in the form "data/%d". So for example: tools/git-sync-deps bin/gn gen out/debug ninja -C out/debug dm skp_parser out/debug/dm -m grayscale -w /tmp/dm --config skp out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp | less out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp | grep data out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp data/0 | file - out/debug/skp_parser /tmp/dm/skp/gm/grayscalejpg.skp data/0 > /tmp/data0.png "data/0" is an image that the SKP serializer has encoded as PNG. */ int main(int argc, char** argv) { if (argc < 2) { SkDebugf("Usage:\n %s SKP_FILE [DATA_URL]\n", argv[0]); return 1; } SkFILEStream input(argv[1]); if (!input.isValid()) { SkDebugf("Bad file: '%s'\n", argv[1]); return 2; } sk_sp<SkPicture> pic = SkPicture::MakeFromStream(&input); if (!pic) { SkDebugf("Bad skp: '%s'\n", argv[1]); return 3; } SkISize size = pic->cullRect().roundOut().size(); SkDebugCanvas debugCanvas(size.width(), size.height()); pic->playback(&debugCanvas); std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); UrlDataManager dataManager(SkString("data")); Json::Value json = debugCanvas.toJSON( dataManager, debugCanvas.getSize(), nullCanvas.get()); if (argc > 2) { if (UrlDataManager::UrlData* data = dataManager.getDataFromUrl(SkString(argv[2]))) { SkData* skdata = data->fData.get(); SkASSERT(skdata); #ifdef SK_BUILD_FOR_WIN fflush(stdout); (void)_setmode(_fileno(stdout), _O_BINARY); #endif fwrite(skdata->data(), skdata->size(), 1, stdout); } else { SkDebugf("Bad data url.\n"); return 4; } } else { Json::StyledStreamWriter(" ").write(std::cout, json); } return 0; }
TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) { setFrameStatus(ImageFrame::FramePartial); char buffer[100 * 100 * 4]; m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); EXPECT_EQ(1, m_decodeRequestCount); EXPECT_EQ(0, m_decodersDestroyed); SkData* data = m_generator->refEncodedData(); EXPECT_EQ(nullptr, data); // LocalFrame can now be decoded completely. setFrameStatus(ImageFrame::FrameComplete); addNewData(); // addNewData is calling m_generator->setData with allDataReceived == false, which means that // refEncodedData should return null. data = m_generator->refEncodedData(); EXPECT_EQ(nullptr, data); OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("DecodeThread")); thread->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&decodeThreadMain, AllowCrossThreadAccess(m_generator.get())))); thread.clear(); EXPECT_EQ(2, m_decodeRequestCount); EXPECT_EQ(1, m_decodersDestroyed); // Decoder created again. m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); EXPECT_EQ(3, m_decodeRequestCount); addNewData(true); data = m_generator->refEncodedData(); ASSERT_TRUE(data); // To prevent data writting, SkData::unique() should be false. ASSERT_TRUE(!data->unique()); // Thread will also ref and unref the data. thread = adoptPtr(Platform::current()->createThread("RefEncodedDataThread")); thread->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&decodeThreadWithRefEncodedMain, AllowCrossThreadAccess(m_generator.get())))); thread.clear(); EXPECT_EQ(4, m_decodeRequestCount); data->unref(); // m_generator is holding the only reference to SkData now. ASSERT_TRUE(data->unique()); data = m_generator->refEncodedData(); ASSERT_TRUE(data && !data->unique()); // Delete generator, and SkData should have the only reference. m_generator = nullptr; ASSERT_TRUE(data->unique()); data->unref(); }
void makeCubeData() { fCubeDimension = 32; fCubeData = SkData::NewUninitialized(sizeof(SkColor) * fCubeDimension * fCubeDimension * fCubeDimension); SkColor* pixels = (SkColor*)(fCubeData->writable_data()); SkAutoTMalloc<uint8_t> lutMemory(fCubeDimension); uint8_t* lut = lutMemory.get(); const int maxIndex = fCubeDimension - 1; for (int i = 0; i < fCubeDimension; ++i) { // Make an invert lut, but the content of // the lut shouldn't affect performance. lut[i] = ((maxIndex - i) * 255) / maxIndex; } for (int r = 0; r < fCubeDimension; ++r) { for (int g = 0; g < fCubeDimension; ++g) { for (int b = 0; b < fCubeDimension; ++b) { pixels[(fCubeDimension * ((fCubeDimension * b) + g)) + r] = SkColorSetARGB(0xFF, lut[r], lut[g], lut[b]); } } } }
// static void SkPDFUtils::EmitPath(const SkPath& path, SkPaint::Style paintStyle, SkWStream* content) { // Filling a path with no area results in a drawing in PDF renderers but // Chrome expects to be able to draw some such entities with no visible // result, so we detect those cases and discard the drawing for them. // Specifically: moveTo(X), lineTo(Y) and moveTo(X), lineTo(X), lineTo(Y). enum SkipFillState { kEmpty_SkipFillState = 0, kSingleLine_SkipFillState = 1, kNonSingleLine_SkipFillState = 2, }; SkipFillState fillState = kEmpty_SkipFillState; if (paintStyle != SkPaint::kFill_Style) { fillState = kNonSingleLine_SkipFillState; } SkPoint lastMovePt = SkPoint::Make(0,0); SkDynamicMemoryWStream currentSegment; SkPoint args[4]; SkPath::Iter iter(path, false); for (SkPath::Verb verb = iter.next(args); verb != SkPath::kDone_Verb; verb = iter.next(args)) { // args gets all the points, even the implicit first point. switch (verb) { case SkPath::kMove_Verb: MoveTo(args[0].fX, args[0].fY, ¤tSegment); lastMovePt = args[0]; fillState = kEmpty_SkipFillState; break; case SkPath::kLine_Verb: AppendLine(args[1].fX, args[1].fY, ¤tSegment); if (fillState == kEmpty_SkipFillState) { if (args[0] != lastMovePt) { fillState = kSingleLine_SkipFillState; } } else if (fillState == kSingleLine_SkipFillState) { fillState = kNonSingleLine_SkipFillState; } break; case SkPath::kQuad_Verb: { SkPoint cubic[4]; SkConvertQuadToCubic(args, cubic); AppendCubic(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY, ¤tSegment); fillState = kNonSingleLine_SkipFillState; break; } case SkPath::kCubic_Verb: AppendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY, args[3].fX, args[3].fY, ¤tSegment); fillState = kNonSingleLine_SkipFillState; break; case SkPath::kClose_Verb: if (fillState != kSingleLine_SkipFillState) { ClosePath(¤tSegment); SkData* data = currentSegment.copyToData(); content->write(data->data(), data->size()); data->unref(); } currentSegment.reset(); break; default: SkASSERT(false); break; } } if (currentSegment.bytesWritten() > 0) { SkData* data = currentSegment.copyToData(); content->write(data->data(), data->size()); data->unref(); } }
// assumes context is a SkData static void sk_dataref_releaseproc(const void*, size_t, void* context) { SkData* src = reinterpret_cast<SkData*>(context); src->unref(); }
static void test_gatherpixelrefs(skiatest::Reporter* reporter) { const int IW = 8; const int IH = IW; const SkScalar W = SkIntToScalar(IW); const SkScalar H = W; static const int N = 4; SkBitmap bm[N]; SkPixelRef* refs[N]; const SkPoint pos[] = { { 0, 0 }, { W, 0 }, { 0, H }, { W, H } }; // Our convention is that the color components contain the index of their // corresponding bitmap/pixelref for (int i = 0; i < N; ++i) { make_bm(&bm[i], IW, IH, SkColorSetARGB(0xFF, i, i, i), true); refs[i] = bm[i].pixelRef(); } static const DrawBitmapProc procs[] = { drawbitmap_proc, drawbitmaprect_proc, drawshader_proc }; SkRandom rand; for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) { SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k])); REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0); // quick check for a small piece of each quadrant, which should just // contain 1 bitmap. for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) { SkRect r; r.set(2, 2, W - 2, H - 2); r.offset(pos[i].fX, pos[i].fY); SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r)); REPORTER_ASSERT(reporter, data); if (data) { int count = static_cast<int>(data->size() / sizeof(SkPixelRef*)); REPORTER_ASSERT(reporter, 1 == count); REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]); } } // Test a bunch of random (mostly) rects, and compare the gather results // with a deduced list of refs by looking at the colors drawn. for (int j = 0; j < 100; ++j) { SkRect r; rand_rect(&r, rand, 2*W, 2*H); SkBitmap result; draw(pic, r, &result); SkTDArray<SkPixelRef*> array; SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); size_t dataSize = data ? data->size() : 0; int gatherCount = static_cast<int>(dataSize / sizeof(SkPixelRef*)); SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize); SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL; SkAutoDataUnref adu(data); gather_from_colors(result, refs, N, &array); /* * GatherPixelRefs is conservative, so it can return more bitmaps * that we actually can see (usually because of conservative bounds * inflation for antialiasing). Thus our check here is only that * Gather didn't miss any that we actually saw. Even that isn't * a strict requirement on Gather, which is meant to be quick and * only mostly-correct, but at the moment this test should work. */ for (int i = 0; i < array.count(); ++i) { bool found = find(gatherRefs, array[i], gatherCount); REPORTER_ASSERT(reporter, found); #if 0 // enable this block of code to debug failures, as it will rerun // the case that failed. if (!found) { SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); size_t dataSize = data ? data->size() : 0; } #endif } } } }
int SkSocket::readPacket(void (*onRead)(int, const void*, size_t, DataType, void*), void* context) { if (!fConnected || !fReady || NULL == onRead || NULL == context || fReadSuspended) return -1; int totalBytesRead = 0; char packet[PACKET_SIZE]; for (int i = 0; i <= fMaxfd; ++i) { if (!FD_ISSET (i, &fMasterSet)) continue; memset(packet, 0, PACKET_SIZE); SkDynamicMemoryWStream stream; int attempts = 0; bool failure = false; int bytesReadInTransfer = 0; int bytesReadInPacket = 0; header h; h.done = false; h.bytes = 0; while (!h.done && fConnected && !failure) { int retval = read(i, packet + bytesReadInPacket, PACKET_SIZE - bytesReadInPacket); ++attempts; if (retval < 0) { #ifdef NONBLOCKING_SOCKETS if (errno == EWOULDBLOCK || errno == EAGAIN) { if (bytesReadInPacket > 0 || bytesReadInTransfer > 0) continue; //incomplete packet or frame, keep tring else break; //nothing to read } #endif //SkDebugf("Read() failed with error: %s\n", strerror(errno)); failure = true; break; } if (retval == 0) { //SkDebugf("Peer closed connection or connection failed\n"); failure = true; break; } SkASSERT(retval > 0); bytesReadInPacket += retval; if (bytesReadInPacket < PACKET_SIZE) { //SkDebugf("Read %d/%d\n", bytesReadInPacket, PACKET_SIZE); continue; //incomplete packet, keep trying } SkASSERT((bytesReadInPacket == PACKET_SIZE) && !failure); memcpy(&h.done, packet, sizeof(bool)); memcpy(&h.bytes, packet + sizeof(bool), sizeof(int)); memcpy(&h.type, packet + sizeof(bool) + sizeof(int), sizeof(DataType)); if (h.bytes > CONTENT_SIZE || h.bytes <= 0) { //SkDebugf("bad packet\n"); failure = true; break; } //SkDebugf("read packet(done:%d, bytes:%d) from fd:%d in %d tries\n", // h.done, h.bytes, fSockfd, attempts); stream.write(packet + HEADER_SIZE, h.bytes); bytesReadInPacket = 0; attempts = 0; bytesReadInTransfer += h.bytes; } if (failure) { onRead(i, NULL, 0, h.type, context); this->onFailedConnection(i); continue; } if (bytesReadInTransfer > 0) { SkData* data = stream.copyToData(); SkASSERT(data->size() == bytesReadInTransfer); onRead(i, data->data(), data->size(), h.type, context); data->unref(); totalBytesRead += bytesReadInTransfer; } } return totalBytesRead; }
int main(int argc, char** argv) { #ifdef MTK_AOSP_ENHANCEMENT // work around for SIGPIPE NE caused by abnormal system status signal(SIGPIPE, SIG_IGN); ALOGD("[Screencap] main"); #endif ProcessState::self()->startThreadPool(); const char* pname = argv[0]; bool png = false; int32_t displayId = DEFAULT_DISPLAY_ID; int c; while ((c = getopt(argc, argv, "phd:")) != -1) { switch (c) { case 'p': png = true; break; case 'd': displayId = atoi(optarg); 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, s, h, f; size_t size = 0; ScreenshotClient screenshot; sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId); if (display != NULL && screenshot.update(display, Rect(), false) == NO_ERROR) { base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); #ifdef MTK_AOSP_ENHANCEMENT ALOGD("[Screencap] screenshot w:%d h:%d s:%d f:%d", w, h, s, f); #endif } 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) { #ifdef MTK_AOSP_ENHANCEMENT size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres_virtual) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres_virtual; ALOGD("[Screencap] VSCREENINFO w:%d h:%d s:%d f:%d", w, h, s, f); #else size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; s = vinfo.xres; #endif 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) { const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType); SkBitmap b; b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f)); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality); SkData* streamData = stream.copyToData(); write(fd, streamData->data(), streamData->size()); streamData->unref(); } else { write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); size_t Bpp = bytesPerPixel(f); for (size_t y=0 ; y<h ; y++) { write(fd, base, w*Bpp); base = (void *)((char *)base + s*Bpp); } } } close(fd); if (mapbase != MAP_FAILED) { munmap((void *)mapbase, mapsize); } return 0; }