~BufferManager() { // nullptr out the entries that are really free list links rather than ptrs before deleting. intptr_t curr = fFreeListHead; while (kFreeListEnd != curr) { intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]); fBuffers[SkToS32(curr)] = nullptr; curr = next; } fBuffers.deleteAll(); }
void SkBinaryWriteBuffer::writeTypeface(SkTypeface* obj) { if (fDeduper) { this->write32(fDeduper->findOrDefineTypeface(obj)); return; } // Write 32 bits (signed) // 0 -- default font // >0 -- index // <0 -- custom (serial procs) if (obj == nullptr) { fWriter.write32(0); } else if (fProcs.fTypefaceProc) { auto data = fProcs.fTypefaceProc(obj, fProcs.fTypefaceCtx); if (data) { size_t size = data->size(); if (!SkTFitsIn<int32_t>(size)) { size = 0; // fall back to default font } int32_t ssize = SkToS32(size); fWriter.write32(-ssize); // negative to signal custom if (size) { this->writePad32(data->data(), size); } return; } // no data means fall through for std behavior } fWriter.write32(fTFSet ? fTFSet->add(obj) : 0); }
/* Format: * (subset) bounds * size (31bits) * data [ encoded, with raw width/height ] */ void SkBinaryWriteBuffer::writeImage(const SkImage* image) { if (fDeduper) { this->write32(fDeduper->findOrDefineImage(const_cast<SkImage*>(image))); return; } const SkIRect bounds = SkImage_getSubset(image); this->writeIRect(bounds); sk_sp<SkData> data; if (fProcs.fImageProc) { data = fProcs.fImageProc(const_cast<SkImage*>(image), fProcs.fImageCtx); } if (!data) { data = image->encodeToData(); } size_t size = data ? data->size() : 0; if (!SkTFitsIn<int32_t>(size)) { size = 0; // too big to store } this->write32(SkToS32(size)); // writing 0 signals failure if (size) { this->writePad32(data->data(), size); } }
// Xref table and footer void SkPDFObjectSerializer::serializeFooter(SkWStream* wStream, const sk_sp<SkPDFObject> docCatalog, sk_sp<SkPDFObject> id) { this->serializeObjects(wStream); int32_t xRefFileOffset = this->offset(wStream); // Include the special zeroth object in the count. int32_t objCount = SkToS32(fOffsets.count() + 1); wStream->writeText("xref\n0 "); wStream->writeDecAsText(objCount); wStream->writeText("\n0000000000 65535 f \n"); for (int i = 0; i < fOffsets.count(); i++) { wStream->writeBigDecAsText(fOffsets[i], 10); wStream->writeText(" 00000 n \n"); } SkPDFDict trailerDict; trailerDict.insertInt("Size", objCount); SkASSERT(docCatalog); trailerDict.insertObjRef("Root", docCatalog); SkASSERT(fInfoDict); trailerDict.insertObjRef("Info", std::move(fInfoDict)); if (id) { trailerDict.insertObject("ID", std::move(id)); } wStream->writeText("trailer\n"); trailerDict.emitObject(wStream, fObjNumMap); wStream->writeText("\nstartxref\n"); wStream->writeBigDecAsText(xRefFileOffset); wStream->writeText("\n%%EOF"); }
size_t SkMask::computeTotalImageSize() const { size_t size = this->computeImageSize(); if (fFormat == SkMask::k3D_Format) { size = safeMul32(SkToS32(size), 3); } return size; }
SkString* SkObjectParser::TextToString(const void* text, size_t byteLength, SkPaint::TextEncoding encoding) { SkString* decodedText = new SkString(); switch (encoding) { case SkPaint::kUTF8_TextEncoding: { decodedText->append("UTF-8: "); decodedText->append((const char*)text, byteLength); break; } case SkPaint::kUTF16_TextEncoding: { decodedText->append("UTF-16: "); size_t sizeNeeded = SkUTF16_ToUTF8((uint16_t*)text, SkToS32(byteLength / 2), nullptr); SkAutoSTMalloc<0x100, char> utf8(sizeNeeded); SkUTF16_ToUTF8((uint16_t*)text, SkToS32(byteLength / 2), utf8); decodedText->append(utf8, sizeNeeded); break; } case SkPaint::kUTF32_TextEncoding: { decodedText->append("UTF-32: "); const SkUnichar* begin = (const SkUnichar*)text; const SkUnichar* end = (const SkUnichar*)((const char*)text + byteLength); for (const SkUnichar* unichar = begin; unichar < end; ++unichar) { decodedText->appendUnichar(*unichar); } break; } case SkPaint::kGlyphID_TextEncoding: { decodedText->append("GlyphID: "); const uint16_t* begin = (const uint16_t*)text; const uint16_t* end = (const uint16_t*)((const char*)text + byteLength); for (const uint16_t* glyph = begin; glyph < end; ++glyph) { decodedText->append("0x"); decodedText->appendHex(*glyph); decodedText->append(" "); } break; } default: decodedText->append("Unknown text encoding."); break; } return decodedText; }
void* ThreadSafePipeController::requestBlock(size_t minRequest, size_t *actual) { if (fBlock) { // Save the previous block for later PipeBlock previousBloc(fBlock, fBytesWritten); fBlockList.push(previousBloc); } int32_t blockSize = SkMax32(SkToS32(minRequest), kMinBlockSize); fBlock = fAllocator.allocThrow(blockSize); fBytesWritten = 0; *actual = blockSize; return fBlock; }
std::unique_ptr<SkAdvancedTypefaceMetrics> SkTestTypeface::onGetAdvancedMetrics() const { // pdf only std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics); info->fFontName.set(fTestFont->fName); int glyphCount = this->onCountGlyphs(); SkTDArray<SkUnichar>& toUnicode = info->fGlyphToUnicode; toUnicode.setCount(glyphCount); SkASSERT(glyphCount == SkToInt(fTestFont->fCharCodesCount)); for (int gid = 0; gid < glyphCount; ++gid) { toUnicode[gid] = SkToS32(fTestFont->fCharCodes[gid]); } return info; }
SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info, size_t requestedRowBytes, SkColorTable* ctable) { if (!is_valid(info, ctable)) { return NULL; } int32_t minRB = SkToS32(info.minRowBytes()); if (minRB < 0) { return NULL; // allocation will be too large } if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) { return NULL; // cannot meet requested rowbytes } int32_t rowBytes; if (requestedRowBytes) { rowBytes = SkToS32(requestedRowBytes); } else { rowBytes = minRB; } int64_t bigSize = (int64_t)info.fHeight * rowBytes; if (!sk_64_isS32(bigSize)) { return NULL; } size_t size = sk_64_asS32(bigSize); SkASSERT(size >= info.getSafeSize(rowBytes)); void* addr = sk_malloc_flags(size, 0); if (NULL == addr) { return NULL; } return SkNEW_ARGS(SkMallocPixelRef, (info, addr, rowBytes, ctable, sk_free_releaseproc, NULL)); }
sk_sp<SkPixelRef> SkMallocPixelRef::MakeUsing(void*(*alloc)(size_t), const SkImageInfo& info, size_t requestedRowBytes, sk_sp<SkColorTable> ctable) { if (!is_valid(info, ctable.get())) { return nullptr; } // only want to permit 31bits of rowBytes int64_t minRB = (int64_t)info.minRowBytes64(); if (minRB < 0 || !sk_64_isS32(minRB)) { return nullptr; // allocation will be too large } if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) { return nullptr; // cannot meet requested rowbytes } int32_t rowBytes; if (requestedRowBytes) { rowBytes = SkToS32(requestedRowBytes); } else { rowBytes = minRB; } int64_t bigSize = (int64_t)info.height() * rowBytes; if (!sk_64_isS32(bigSize)) { return nullptr; } size_t size = sk_64_asS32(bigSize); SkASSERT(size >= info.getSafeSize(rowBytes)); void* addr = alloc(size); if (nullptr == addr) { return nullptr; } return sk_sp<SkPixelRef>(new SkMallocPixelRef(info, addr, rowBytes, std::move(ctable), sk_free_releaseproc, nullptr)); }
bool SkXMLParser::parse(SkStream& docStream) { ParsingContext ctx(this); if (!ctx.fXMLParser) { SkDebugf("could not create XML parser\n"); return false; } XML_SetUserData(ctx.fXMLParser, &ctx); XML_SetElementHandler(ctx.fXMLParser, start_element_handler, end_element_handler); XML_SetCharacterDataHandler(ctx.fXMLParser, text_handler); // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340. XML_SetEntityDeclHandler(ctx.fXMLParser, entity_decl_handler); static const int kBufferSize = 512 SkDEBUGCODE( - 507); bool done = false; do { void* buffer = XML_GetBuffer(ctx.fXMLParser, kBufferSize); if (!buffer) { SkDebugf("could not buffer enough to continue\n"); return false; } size_t len = docStream.read(buffer, kBufferSize); done = docStream.isAtEnd(); XML_Status status = XML_ParseBuffer(ctx.fXMLParser, SkToS32(len), done); if (XML_STATUS_ERROR == status) { XML_Error error = XML_GetErrorCode(ctx.fXMLParser); int line = XML_GetCurrentLineNumber(ctx.fXMLParser); int column = XML_GetCurrentColumnNumber(ctx.fXMLParser); const XML_LChar* errorString = XML_ErrorString(error); SkDebugf("parse error @%d:%d: %d (%s).\n", line, column, error, errorString); return false; } } while (!done); return true; }
static void setup_benchmark(sk_tools::PictureBenchmark* benchmark) { sk_tools::PictureRenderer::DrawFilterFlags drawFilters[SkDrawFilter::kTypeCount]; sk_bzero(drawFilters, sizeof(drawFilters)); if (FLAGS_filter.count() > 0) { const char* filters = FLAGS_filter[0]; const char* colon = strchr(filters, ':'); if (colon) { int32_t type = -1; size_t typeLen = colon - filters; for (size_t tIndex = 0; tIndex < kFilterTypesCount; ++tIndex) { if (typeLen == strlen(gFilterTypes[tIndex]) && !strncmp(filters, gFilterTypes[tIndex], typeLen)) { type = SkToS32(tIndex); break; } } if (type < 0) { SkString err; err.printf("Unknown type for --filter %s\n", filters); gLogger.logError(err); exit(-1); } int flag = -1; size_t flagLen = strlen(filters) - typeLen - 1; for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) { if (flagLen == strlen(gFilterFlags[fIndex]) && !strncmp(colon + 1, gFilterFlags[fIndex], flagLen)) { flag = 1 << fIndex; break; } } if (flag < 0) { SkString err; err.printf("Unknown flag for --filter %s\n", filters); gLogger.logError(err); exit(-1); } for (int index = 0; index < SkDrawFilter::kTypeCount; ++index) { if (type != SkDrawFilter::kTypeCount && index != type) { continue; } drawFilters[index] = (sk_tools::PictureRenderer::DrawFilterFlags) (drawFilters[index] | flag); } } else { SkString err; err.printf("Unknown arg for --filter %s : missing colon\n", filters); gLogger.logError(err); exit(-1); } } if (FLAGS_timers.count() > 0) { size_t index = 0; bool timerWall = false; bool truncatedTimerWall = false; bool timerCpu = false; bool truncatedTimerCpu = false; bool timerGpu = false; while (index < strlen(FLAGS_timers[0])) { switch (FLAGS_timers[0][index]) { case 'w': timerWall = true; break; case 'c': timerCpu = true; break; case 'W': truncatedTimerWall = true; break; case 'C': truncatedTimerCpu = true; break; case 'g': timerGpu = true; break; default: SkDebugf("mystery character\n"); break; } index++; } benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu, truncatedTimerCpu, timerGpu); } SkString errorString; SkAutoTUnref<sk_tools::PictureRenderer> renderer(parseRenderer(errorString, kBench_PictureTool)); if (errorString.size() > 0) { gLogger.logError(errorString); } if (NULL == renderer.get()) { exit(-1); } if (FLAGS_timeIndividualTiles) { sk_tools::TiledPictureRenderer* tiledRenderer = renderer->getTiledRenderer(); if (NULL == tiledRenderer) { gLogger.logError("--timeIndividualTiles requires tiled rendering.\n"); exit(-1); } if (!tiledRenderer->supportsTimingIndividualTiles()) { gLogger.logError("This renderer does not support --timeIndividualTiles.\n"); exit(-1); } benchmark->setTimeIndividualTiles(true); } benchmark->setPurgeDecodedTex(FLAGS_purgeDecodedTex); benchmark->setPreprocess(FLAGS_preprocess); if (FLAGS_readPath.count() < 1) { gLogger.logError(".skp files or directories are required.\n"); exit(-1); } renderer->setDrawFilters(drawFilters, filtersName(drawFilters)); if (FLAGS_logPerIter) { benchmark->setTimerResultType(TimerData::kPerIter_Result); } else if (FLAGS_min) { benchmark->setTimerResultType(TimerData::kMin_Result); } else { benchmark->setTimerResultType(TimerData::kAvg_Result); } benchmark->setRenderer(renderer); benchmark->setRepeats(FLAGS_repeat); benchmark->setWriter(&gWriter); }
static bool emit_pdf_document(const SkTDArray<const SkPDFDevice*>& pageDevices, SkWStream* stream) { if (pageDevices.isEmpty()) { return false; } SkTDArray<SkPDFDict*> pages; SkAutoTUnref<SkPDFDict> dests(SkNEW(SkPDFDict)); for (int i = 0; i < pageDevices.count(); i++) { SkASSERT(pageDevices[i]); SkASSERT(i == 0 || pageDevices[i - 1]->getCanon() == pageDevices[i]->getCanon()); SkAutoTUnref<SkPDFDict> page(create_pdf_page(pageDevices[i])); pageDevices[i]->appendDestinations(dests, page.get()); pages.push(page.detach()); } SkTDArray<SkPDFDict*> pageTree; SkAutoTUnref<SkPDFDict> docCatalog(SkNEW_ARGS(SkPDFDict, ("Catalog"))); SkPDFDict* pageTreeRoot; generate_page_tree(pages, &pageTree, &pageTreeRoot); docCatalog->insertObjRef("Pages", SkRef(pageTreeRoot)); if (dests->size() > 0) { docCatalog->insertObjRef("Dests", dests.detach()); } /* TODO(vandebo): output intent SkAutoTUnref<SkPDFDict> outputIntent = new SkPDFDict("OutputIntent"); outputIntent->insertName("S", "GTS_PDFA1"); outputIntent->insertString("OutputConditionIdentifier", "sRGB"); SkAutoTUnref<SkPDFArray> intentArray(new SkPDFArray); intentArray->appendObject(SkRef(outputIntent.get())); docCatalog->insertObject("OutputIntent", intentArray.detach()); */ // Build font subsetting info before proceeding. SkPDFSubstituteMap substitutes; perform_font_subsetting(pageDevices, &substitutes); SkPDFObjNumMap objNumMap; if (objNumMap.addObject(docCatalog.get())) { docCatalog->addResources(&objNumMap, substitutes); } size_t baseOffset = stream->bytesWritten(); emit_pdf_header(stream); SkTDArray<int32_t> offsets; for (int i = 0; i < objNumMap.objects().count(); ++i) { SkPDFObject* object = objNumMap.objects()[i]; size_t offset = stream->bytesWritten(); // This assert checks that size(pdf_header) > 0 and that // the output stream correctly reports bytesWritten(). SkASSERT(offset > baseOffset); offsets.push(SkToS32(offset - baseOffset)); SkASSERT(object == substitutes.getSubstitute(object)); SkASSERT(objNumMap.getObjectNumber(object) == i + 1); stream->writeDecAsText(i + 1); stream->writeText(" 0 obj\n"); // Generation number is always 0. object->emitObject(stream, objNumMap, substitutes); stream->writeText("\nendobj\n"); } int32_t xRefFileOffset = SkToS32(stream->bytesWritten() - baseOffset); // Include the zeroth object in the count. int32_t objCount = SkToS32(offsets.count() + 1); stream->writeText("xref\n0 "); stream->writeDecAsText(objCount); stream->writeText("\n0000000000 65535 f \n"); for (int i = 0; i < offsets.count(); i++) { SkASSERT(offsets[i] > 0); stream->writeBigDecAsText(offsets[i], 10); stream->writeText(" 00000 n \n"); } emit_pdf_footer(stream, objNumMap, substitutes, docCatalog.get(), objCount, xRefFileOffset); // The page tree has both child and parent pointers, so it creates a // reference cycle. We must clear that cycle to properly reclaim memory. for (int i = 0; i < pageTree.count(); i++) { pageTree[i]->clear(); } pageTree.safeUnrefAll(); pages.unrefAll(); return true; }
int32_t SkPDFObjectSerializer::offset(SkWStream* wStream) { size_t offset = wStream->bytesWritten(); SkASSERT(offset > fBaseOffset); return SkToS32(offset - fBaseOffset); }
bool SkPatchUtils::getVertexData(SkPatchUtils::VertexData* data, const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4], int lodX, int lodY) { if (lodX < 1 || lodY < 1 || NULL == cubics || NULL == data) { return false; } // check for overflow in multiplication const int64_t lodX64 = (lodX + 1), lodY64 = (lodY + 1), mult64 = lodX64 * lodY64; if (mult64 > SK_MaxS32) { return false; } data->fVertexCount = SkToS32(mult64); // it is recommended to generate draw calls of no more than 65536 indices, so we never generate // more than 60000 indices. To accomplish that we resize the LOD and vertex count if (data->fVertexCount > 10000 || lodX > 200 || lodY > 200) { SkScalar weightX = static_cast<SkScalar>(lodX) / (lodX + lodY); SkScalar weightY = static_cast<SkScalar>(lodY) / (lodX + lodY); // 200 comes from the 100 * 2 which is the max value of vertices because of the limit of // 60000 indices ( sqrt(60000 / 6) that comes from data->fIndexCount = lodX * lodY * 6) lodX = static_cast<int>(weightX * 200); lodY = static_cast<int>(weightY * 200); data->fVertexCount = (lodX + 1) * (lodY + 1); } data->fIndexCount = lodX * lodY * 6; data->fPoints = SkNEW_ARRAY(SkPoint, data->fVertexCount); data->fIndices = SkNEW_ARRAY(uint16_t, data->fIndexCount); // if colors is not null then create array for colors SkPMColor colorsPM[kNumCorners]; if (NULL != colors) { // premultiply colors to avoid color bleeding. for (int i = 0; i < kNumCorners; i++) { colorsPM[i] = SkPreMultiplyColor(colors[i]); } data->fColors = SkNEW_ARRAY(uint32_t, data->fVertexCount); } // if texture coordinates are not null then create array for them if (NULL != texCoords) { data->fTexCoords = SkNEW_ARRAY(SkPoint, data->fVertexCount); } SkPoint pts[kNumPtsCubic]; SkPatchUtils::getBottomCubic(cubics, pts); FwDCubicEvaluator fBottom(pts); SkPatchUtils::getTopCubic(cubics, pts); FwDCubicEvaluator fTop(pts); SkPatchUtils::getLeftCubic(cubics, pts); FwDCubicEvaluator fLeft(pts); SkPatchUtils::getRightCubic(cubics, pts); FwDCubicEvaluator fRight(pts); fBottom.restart(lodX); fTop.restart(lodX); SkScalar u = 0.0f; int stride = lodY + 1; for (int x = 0; x <= lodX; x++) { SkPoint bottom = fBottom.next(), top = fTop.next(); fLeft.restart(lodY); fRight.restart(lodY); SkScalar v = 0.f; for (int y = 0; y <= lodY; y++) { int dataIndex = x * (lodY + 1) + y; SkPoint left = fLeft.next(), right = fRight.next(); SkPoint s0 = SkPoint::Make((1.0f - v) * top.x() + v * bottom.x(), (1.0f - v) * top.y() + v * bottom.y()); SkPoint s1 = SkPoint::Make((1.0f - u) * left.x() + u * right.x(), (1.0f - u) * left.y() + u * right.y()); SkPoint s2 = SkPoint::Make( (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].x() + u * fTop.getCtrlPoints()[3].x()) + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].x() + u * fBottom.getCtrlPoints()[3].x()), (1.0f - v) * ((1.0f - u) * fTop.getCtrlPoints()[0].y() + u * fTop.getCtrlPoints()[3].y()) + v * ((1.0f - u) * fBottom.getCtrlPoints()[0].y() + u * fBottom.getCtrlPoints()[3].y())); data->fPoints[dataIndex] = s0 + s1 - s2; if (NULL != colors) { uint8_t a = uint8_t(bilerp(u, v, SkScalar(SkColorGetA(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetA(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetA(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetA(colorsPM[kBottomRight_Corner])))); uint8_t r = uint8_t(bilerp(u, v, SkScalar(SkColorGetR(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetR(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetR(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetR(colorsPM[kBottomRight_Corner])))); uint8_t g = uint8_t(bilerp(u, v, SkScalar(SkColorGetG(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetG(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetG(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetG(colorsPM[kBottomRight_Corner])))); uint8_t b = uint8_t(bilerp(u, v, SkScalar(SkColorGetB(colorsPM[kTopLeft_Corner])), SkScalar(SkColorGetB(colorsPM[kTopRight_Corner])), SkScalar(SkColorGetB(colorsPM[kBottomLeft_Corner])), SkScalar(SkColorGetB(colorsPM[kBottomRight_Corner])))); data->fColors[dataIndex] = SkPackARGB32(a,r,g,b); } if (NULL != texCoords) { data->fTexCoords[dataIndex] = SkPoint::Make( bilerp(u, v, texCoords[kTopLeft_Corner].x(), texCoords[kTopRight_Corner].x(), texCoords[kBottomLeft_Corner].x(), texCoords[kBottomRight_Corner].x()), bilerp(u, v, texCoords[kTopLeft_Corner].y(), texCoords[kTopRight_Corner].y(), texCoords[kBottomLeft_Corner].y(), texCoords[kBottomRight_Corner].y())); } if(x < lodX && y < lodY) { int i = 6 * (x * lodY + y); data->fIndices[i] = x * stride + y; data->fIndices[i + 1] = x * stride + 1 + y; data->fIndices[i + 2] = (x + 1) * stride + 1 + y; data->fIndices[i + 3] = data->fIndices[i]; data->fIndices[i + 4] = data->fIndices[i + 2]; data->fIndices[i + 5] = (x + 1) * stride + y; } v = SkScalarClampMax(v + 1.f / lodY, 1); } u = SkScalarClampMax(u + 1.f / lodX, 1); } return true; }