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();)