// Return the context associated with the next logical typeface, or NULL if // there are no more entries in the fallback chain. SkScalerContext* SkScalerContext::allocNextContext() const { #ifdef SK_BUILD_FOR_ANDROID SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID, fRec.fOrigFontID, fPaintOptionsAndroid); if (0 == newFace) { return NULL; } SkAutoTUnref<SkTypeface> aur(newFace); uint32_t newFontID = newFace->uniqueID(); SkWriteBuffer androidBuffer; fPaintOptionsAndroid.flatten(androidBuffer); SkAutoDescriptor ad(sizeof(fRec) + androidBuffer.bytesWritten() + SkDescriptor::ComputeOverhead(2)); SkDescriptor* desc = ad.getDesc(); desc->init(); SkScalerContext::Rec* newRec = (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(fRec), &fRec); androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag, androidBuffer.bytesWritten(), NULL)); newRec->fFontID = newFontID; desc->computeChecksum(); return newFace->createScalerContext(desc); #else return NULL; #endif }
void SkGPipeCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { NOTIFY_SETUP(this); this->writePaint(paint); // FIXME: this is inefficient but avoids duplicating the blob serialization logic. SkRefCntSet typefaceSet; SkWriteBuffer blobBuffer; blobBuffer.setTypefaceRecorder(&typefaceSet); blob->flatten(blobBuffer); // Unlike most draw ops (which only use one paint/typeface), text blobs may reference // an arbitrary number of typefaces. Since the one-paint-per-op model is not applicable, // we need to serialize these explicitly. TypefaceBuffer typefaceBuffer; size_t typefaceSize = is_cross_process(fFlags) ? this->getCrossProcessTypefaces(typefaceSet, &typefaceBuffer) : this->getInProcessTypefaces(typefaceSet, &typefaceBuffer); // blob byte count + typeface count + x + y + blob data + an index (cross-process) // or pointer (in-process) for each typeface size_t size = 2 * sizeof(uint32_t) + 2 * sizeof(SkScalar) + blobBuffer.bytesWritten() + typefaceSize; if (this->needOpBytes(size)) { this->writeOp(kDrawTextBlob_DrawOp); SkDEBUGCODE(size_t initialOffset = fWriter.bytesWritten();)
SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) { SkWriteBuffer writer; writer.writeFlattenable(flattenable); size_t size = writer.bytesWritten(); auto data = SkData::MakeUninitialized(size); writer.writeToMemory(data->writable_data()); return data.release(); }
static void flatten(const SkFlattenable* flattenable, Json::Value* target, bool sendBinaries) { if (sendBinaries) { SkWriteBuffer buffer; flattenable->flatten(buffer); void* data = sk_malloc_throw(buffer.bytesWritten()); buffer.writeToMemory(data); Json::Value bytes; encode_data(data, buffer.bytesWritten(), &bytes); Json::Value jsonFlattenable; jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_NAME] = Json::Value(flattenable->getTypeName()); jsonFlattenable[SKJSONCANVAS_ATTRIBUTE_BYTES] = bytes; (*target) = jsonFlattenable; free(data); } else { (*target)[SKJSONCANVAS_ATTRIBUTE_DESCRIPTION] = Json::Value(flattenable->getTypeName()); } }
static sk_sp<SkColorFilter> reincarnate_colorfilter(SkFlattenable* obj) { SkWriteBuffer wb; wb.writeFlattenable(obj); size_t size = wb.bytesWritten(); SkAutoSMalloc<1024> storage(size); // make a copy into storage wb.writeToMemory(storage.get()); SkReadBuffer rb(storage.get(), size); return rb.readColorFilter(); }
DEF_TEST(DashPathEffectTest_crbug_348821, r) { SkScalar intervals[] = { 1.76934361e+36f, 2.80259693e-45f }; // Values from bug. const int count = 2; SkScalar phase = SK_ScalarInfinity; // Used to force the bad fInitialDashLength = -1 path. SkAutoTUnref<SkDashPathEffect> dash(SkDashPathEffect::Create(intervals, count, phase)); // nullptr -> refuses to work with flattening framework. REPORTER_ASSERT(r, dash->getFactory() != nullptr); SkWriteBuffer buffer; buffer.writeFlattenable(dash); REPORTER_ASSERT(r, buffer.bytesWritten() > 12); // We'd write 12 if broken, >=40 if not. }
bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { SkASSERT(shouldFlattenBitmaps(fFlags)); SkWriteBuffer buffer; buffer.setNamedFactoryRecorder(fFactorySet); buffer.writeBitmap(bm); this->flattenFactoryNames(); size_t size = buffer.bytesWritten(); if (this->needOpBytes(size)) { this->writeOp(kDef_Bitmap_DrawOp, 0, slot); void* dst = static_cast<void*>(fWriter.reserve(size)); buffer.writeToMemory(dst); return true; } return false; }
DEF_TEST(Paint_flattening, reporter) { const SkFilterQuality levels[] = { kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality, kHigh_SkFilterQuality, }; const SkPaint::Hinting hinting[] = { SkPaint::kNo_Hinting, SkPaint::kSlight_Hinting, SkPaint::kNormal_Hinting, SkPaint::kFull_Hinting, }; const SkPaint::Align align[] = { SkPaint::kLeft_Align, SkPaint::kCenter_Align, SkPaint::kRight_Align }; const SkPaint::Cap caps[] = { SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap, }; const SkPaint::Join joins[] = { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join, }; const SkPaint::TextEncoding encodings[] = { SkPaint::kUTF8_TextEncoding, SkPaint::kUTF16_TextEncoding, SkPaint::kUTF32_TextEncoding, SkPaint::kGlyphID_TextEncoding, }; const SkPaint::Style styles[] = { SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style, }; #define FOR_SETUP(index, array, setter) \ for (size_t index = 0; index < SK_ARRAY_COUNT(array); ++index) { \ paint.setter(array[index]); \ SkPaint paint; paint.setFlags(0x1234); FOR_SETUP(i, levels, setFilterQuality) FOR_SETUP(j, hinting, setHinting) FOR_SETUP(k, align, setTextAlign) FOR_SETUP(l, caps, setStrokeCap) FOR_SETUP(m, joins, setStrokeJoin) FOR_SETUP(n, encodings, setTextEncoding) FOR_SETUP(p, styles, setStyle) SkWriteBuffer writer; paint.flatten(writer); const uint32_t* written = writer.getWriter32()->contiguousArray(); SkReadBuffer reader(written, writer.bytesWritten()); SkPaint paint2; paint2.unflatten(reader); REPORTER_ASSERT(reporter, paint2 == paint); }}}}}}}