// Sort of like makeSpace(0) but the the additional requirement that we actively shrink the // allocations to just fit the current needs. makeSpace() will only grow, but never shrinks. // void SkPath::shrinkToFit() { const size_t kMinFreeSpaceForShrink = 8; // just made up a small number if (fPathRef->fFreeSpace <= kMinFreeSpaceForShrink) { return; } if (fPathRef->unique()) { int pointCount = fPathRef->fPointCnt; int verbCount = fPathRef->fVerbCnt; size_t ptsSize = sizeof(SkPoint) * pointCount; size_t vrbSize = sizeof(uint8_t) * verbCount; size_t minSize = ptsSize + vrbSize; void* newAlloc = sk_malloc_canfail(minSize); if (!newAlloc) { return; // couldn't allocate the smaller buffer, but that's ok } sk_careful_memcpy(newAlloc, fPathRef->fPoints, ptsSize); sk_careful_memcpy((char*)newAlloc + minSize - vrbSize, fPathRef->verbsMemBegin(), vrbSize); sk_free(fPathRef->fPoints); fPathRef->fPoints = static_cast<SkPoint*>(newAlloc); fPathRef->fVerbs = (uint8_t*)newAlloc + minSize; fPathRef->fFreeSpace = 0; fPathRef->fConicWeights.shrinkToFit(); } else { sk_sp<SkPathRef> pr(new SkPathRef); pr->copy(*fPathRef, 0, 0); fPathRef = std::move(pr); } SkDEBUGCODE(fPathRef->validate();) }
std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> stream, Result* result) { // Header size constants constexpr uint32_t kIcoDirectoryBytes = 6; constexpr uint32_t kIcoDirEntryBytes = 16; // Read the directory header std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]); if (stream->read(dirBuffer.get(), kIcoDirectoryBytes) != kIcoDirectoryBytes) { SkCodecPrintf("Error: unable to read ico directory header.\n"); *result = kIncompleteInput; return nullptr; } // Process the directory header const uint16_t numImages = get_short(dirBuffer.get(), 4); if (0 == numImages) { SkCodecPrintf("Error: No images embedded in ico.\n"); *result = kInvalidInput; return nullptr; } // This structure is used to represent the vital information about entries // in the directory header. We will obtain this information for each // directory entry. struct Entry { uint32_t offset; uint32_t size; }; SkAutoFree dirEntryBuffer(sk_malloc_canfail(sizeof(Entry) * numImages)); if (!dirEntryBuffer) { SkCodecPrintf("Error: OOM allocating ICO directory for %i images.\n", numImages); *result = kInternalError; return nullptr; } auto* directoryEntries = reinterpret_cast<Entry*>(dirEntryBuffer.get()); // Iterate over directory entries for (uint32_t i = 0; i < numImages; i++) { uint8_t entryBuffer[kIcoDirEntryBytes]; if (stream->read(entryBuffer, kIcoDirEntryBytes) != kIcoDirEntryBytes) { SkCodecPrintf("Error: Dir entries truncated in ico.\n"); *result = kIncompleteInput; return nullptr; } // The directory entry contains information such as width, height, // bits per pixel, and number of colors in the color palette. We will // ignore these fields since they are repeated in the header of the // embedded image. In the event of an inconsistency, we would always // defer to the value in the embedded header anyway. // Specifies the size of the embedded image, including the header uint32_t size = get_int(entryBuffer, 8); // Specifies the offset of the embedded image from the start of file. // It does not indicate the start of the pixel data, but rather the // start of the embedded image header. uint32_t offset = get_int(entryBuffer, 12); // Save the vital fields directoryEntries[i].offset = offset; directoryEntries[i].size = size; } // Default Result, if no valid embedded codecs are found. *result = kInvalidInput; // It is "customary" that the embedded images will be stored in order of // increasing offset. However, the specification does not indicate that // they must be stored in this order, so we will not trust that this is the // case. Here we sort the embedded images by increasing offset. struct EntryLessThan { bool operator() (Entry a, Entry b) const { return a.offset < b.offset; } }; EntryLessThan lessThan; SkTQSort(directoryEntries, &directoryEntries[numImages - 1], lessThan); // Now will construct a candidate codec for each of the embedded images uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes; std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs( new SkTArray<std::unique_ptr<SkCodec>, true>(numImages)); for (uint32_t i = 0; i < numImages; i++) { uint32_t offset = directoryEntries[i].offset; uint32_t size = directoryEntries[i].size; // Ensure that the offset is valid if (offset < bytesRead) { SkCodecPrintf("Warning: invalid ico offset.\n"); continue; } // If we cannot skip, assume we have reached the end of the stream and // stop trying to make codecs if (stream->skip(offset - bytesRead) != offset - bytesRead) { SkCodecPrintf("Warning: could not skip to ico offset.\n"); break; } bytesRead = offset; // Create a new stream for the embedded codec SkAutoFree buffer(sk_malloc_canfail(size)); if (!buffer) { SkCodecPrintf("Warning: OOM trying to create embedded stream.\n"); break; } if (stream->read(buffer.get(), size) != size) { SkCodecPrintf("Warning: could not create embedded stream.\n"); *result = kIncompleteInput; break; } sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size)); auto embeddedStream = SkMemoryStream::Make(data); bytesRead += size; // Check if the embedded codec is bmp or png and create the codec std::unique_ptr<SkCodec> codec; Result dummyResult; if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) { codec = SkPngCodec::MakeFromStream(std::move(embeddedStream), &dummyResult); } else { codec = SkBmpCodec::MakeFromIco(std::move(embeddedStream), &dummyResult); } // Save a valid codec if (nullptr != codec) { codecs->push_back().reset(codec.release()); } } // Recognize if there are no valid codecs if (0 == codecs->count()) { SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n"); return nullptr; } // Use the largest codec as a "suggestion" for image info size_t maxSize = 0; int maxIndex = 0; for (int i = 0; i < codecs->count(); i++) { SkImageInfo info = codecs->operator[](i)->getInfo(); size_t size = info.computeMinByteSize(); if (size > maxSize) { maxSize = size; maxIndex = i; } } auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy(); *result = kSuccess; // The original stream is no longer needed, because the embedded codecs own their // own streams. return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release())); }
SkBmpBaseCodec::SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder) , fSrcBuffer(sk_malloc_canfail(this->srcRowBytes())) {}