blob: 93436da41761f31b243187a92fb0cb908a07e002 [file]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <SkColorFilter.h>
#include <SkSurface.h>
#include "SkFontScanner_FreeType.h"
#include "src/core/SkReadBuffer.h"
//#include "src/core/SkVerticesPriv.h"
#include "src/core/SkWriteBuffer.h"
#include <android/ipcrenderbuffer/RenderBufferOps.h>
#include <android/ipcrenderbuffer/RenderBufferDebugUtils.h>
#include <unordered_map>
#include <unordered_set>
#define DUMP_OPS 0
// #define DUMP_OPS 1
namespace android {
void renderOpToCanvas(IPCServerResourceCache* cache, RenderCommandBuffer* buffer,
IPCRenderBufferOp* op, SkCanvas* canvas,
const std::function<void(int)>& renderProxyCallback,
const SkMatrix& initialMatrix = SkMatrix::I(),
const SkRect& initialClip = SkRect::MakeEmpty()) {
switch (op->type) {
case TYPE_SAVE: {
SaveOp* co = (SaveOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_RESTORE: {
RestoreOp* co = (RestoreOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_SAVELAYER: {
SaveLayerOp* co = (SaveLayerOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_SAVEBEHIND: {
SaveBehindOp* co = (SaveBehindOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CONCAT: {
ConcatOp* co = (ConcatOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_SETMATRIX: {
SetMatrixOp* co = (SetMatrixOp*)op;
co->draw(canvas, initialMatrix, cache);
break;
}
case TYPE_SCALE: {
ScaleOp* co = (ScaleOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_TRANSLATE: {
TranslateOp* co = (TranslateOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CLIPPATH: {
ClipPathOp* co = (ClipPathOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CLIPRECT: {
ClipRectOp* co = (ClipRectOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CLIPRRECT: {
ClipRRectOp* co = (ClipRRectOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CLIPREGION: {
ClipRegionOp* co = (ClipRegionOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_CLIPSHADER: {
ClipShaderOp* co = (ClipShaderOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_RESETCLIP: {
ResetClipOp* co = (ResetClipOp*)op;
co->draw(canvas, initialMatrix, initialClip, cache);
break;
}
case TYPE_DRAWPAINT: {
DrawPaintOp* co = (DrawPaintOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWBEHIND: {
DrawBehindOp* co = (DrawBehindOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWPATH: {
DrawPathOp* co = (DrawPathOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWRECT: {
DrawRectOp* co = (DrawRectOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWREGION: {
DrawRegionOp* co = (DrawRegionOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWOVAL: {
DrawOvalOp* co = (DrawOvalOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWARC: {
DrawArcOp* co = (DrawArcOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWRRECT: {
DrawRRectOp* co = (DrawRRectOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWANNOTATION: {
DrawAnnotationOp* co = (DrawAnnotationOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWDRAWABLE: {
DrawDrawableOp* co = (DrawDrawableOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWPICTURE: {
DrawPictureOp* co = (DrawPictureOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWIMAGE: {
if (!cache) {
ALOGE("DrawImageOp failed due to unpopulated cache.");
break;
}
DrawImageOp* co = (DrawImageOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWIMAGERECT: {
if (!cache) {
ALOGE("DrawImageRectOp failed due to unpopulated cache.");
break;
}
DrawImageRectOp* co = (DrawImageRectOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWTEXTBLOB: {
if (!cache) {
ALOGE("DrawTextBlobOp failed due to unpopulated cache.");
break;
}
DrawTextBlobOp* co = (DrawTextBlobOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWPATCH: {
DrawPatchOp* co = (DrawPatchOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWPOINTS: {
DrawPointsOp* co = (DrawPointsOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWVERTICES: {
DrawVerticesOp* co = (DrawVerticesOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWSKMESH: {
DrawSkMeshOp* co = (DrawSkMeshOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWATLAS: {
DrawAtlasOp* co = (DrawAtlasOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWSHADOWREC: {
DrawShadowRecOp* co = (DrawShadowRecOp*)op;
co->draw(canvas, SkMatrix::I(), cache);
break;
}
case TYPE_DRAWPROXYSURFACECONTROL: {
DrawProxySurfaceControlOp* co = (DrawProxySurfaceControlOp*)op;
// co->draw(canvas, SkMatrix::I(), cache);
renderProxyCallback(co->proxyId);
break;
}
case TYPE_BEGINRENDERTARGET:
case TYPE_ENDRENDERTARGET: {
// Handled by loop
break;
}
default: {
ALOGE("Unexpected op in RenderCommandBuffer %d", op->type);
break;
}
}
}
bool isDrawingOp(uint32_t type) {
switch (type) {
case TYPE_SAVE:
case TYPE_RESTORE:
case TYPE_SAVELAYER:
case TYPE_SAVEBEHIND:
case TYPE_CONCAT:
case TYPE_SETMATRIX:
case TYPE_SCALE:
case TYPE_TRANSLATE:
case TYPE_CLIPPATH:
case TYPE_CLIPRECT:
case TYPE_CLIPRRECT:
case TYPE_CLIPREGION:
case TYPE_CLIPSHADER:
case TYPE_RESETCLIP:
case TYPE_DRAWPROXYSURFACECONTROL: // Questionable
return false;
case TYPE_DRAWPAINT:
case TYPE_DRAWBEHIND:
case TYPE_DRAWPATH:
case TYPE_DRAWRECT:
case TYPE_DRAWREGION:
case TYPE_DRAWOVAL:
case TYPE_DRAWARC:
case TYPE_DRAWRRECT:
case TYPE_DRAWDRRECT:
case TYPE_DRAWANNOTATION:
case TYPE_DRAWDRAWABLE:
case TYPE_DRAWPICTURE:
case TYPE_DRAWIMAGE:
case TYPE_DRAWIMAGERECT:
case TYPE_DRAWIMAGELATTICE:
case TYPE_DRAWTEXTBLOB:
case TYPE_DRAWPATCH:
case TYPE_DRAWPOINTS:
case TYPE_DRAWVERTICES:
case TYPE_DRAWATLAS:
case TYPE_DRAWSHADOWREC:
case TYPE_DRAWVECTORDRAWABLE:
case TYPE_DRAWRIPPLEDRAWABLE:
case TYPE_DRAWWEBVIEW:
case TYPE_DRAWSKMESH:
case TYPE_DRAWMESH:
return true;
default:
return false;
}
}
SkPaint fromShmemPaint(const ShmemPaint& paint, IPCServerResourceCache* serverCache) {
if (!paint.data.data) {
return SkPaint();
}
SkReadBuffer reader(paint.data.data.get(), paint.data.size);
reader.setAllowSkSL(true);
if (serverCache) {
SkDeserialProcs procs;
procs.fImageCtx = serverCache;
procs.fImageProc = [](const void* data, size_t length, void* ctx) -> sk_sp<SkImage> {
if (length != sizeof(uint64_t)) {
return nullptr;
}
uint64_t id;
memcpy(&id, data, sizeof(id));
auto* cache = static_cast<IPCServerResourceCache*>(ctx);
auto it = cache->bitmaps.find(id);
if (it == cache->bitmaps.end()) {
return nullptr;
}
return it->second.image;
};
reader.setDeserialProcs(procs);
}
return SkPaintPriv::Unflatten(reader);
}
bool isClear(const IPCRenderBufferOp* op) {
if (op->type != TYPE_DRAWPAINT) {
return false;
}
DrawPaintOp *dop = (DrawPaintOp *)op;
auto paint = fromShmemPaint(dop->paint, nullptr);
auto color = paint.getColor4f();
if (color.fR == 0.0f && color.fG == 0.0f && color.fB == 0.0f && color.fA == 0.0f) {
return true;
}
return false;
}
bool renderCommandBufferToCanvas(IPCServerResourceCache* cache, RenderCommandBuffer* buffer,
SkCanvas* canvas,
const std::function<void(int)>& renderProxyCallback) {
bool foundFirstDrawingOp = false;
if constexpr (DUMP_OPS) {
ALOGE("Rendering command buffer");
}
while (auto* baseOp = buffer->mRegion->mUploadBuf.peek()) {
auto* op = static_cast<IPCRenderBufferUploadOp*>(baseOp);
if (op->type == TYPE_UPLOADBITMAP) {
UploadBitmap* uo = static_cast<UploadBitmap*>(op);
if (cache) uo->execute(*cache);
} else if (op->type == TYPE_UPLOADTYPEFACE) {
UploadTypeface* uo = static_cast<UploadTypeface*>(op);
if (cache) uo->execute(*cache);
} else if (op->type == TYPE_FREEBITMAP) {
FreeBitmap* fo = static_cast<FreeBitmap*>(op);
if (cache) fo->execute(*cache);
}
buffer->mRegion->mUploadBuf.pop();
}
SkMatrix rootMatrix = canvas->getTotalMatrix();
SkRect rootClip = SkRect::Make(canvas->getDeviceClipBounds());
sk_sp<SkSurface> boundSurface = nullptr;
bool renderingOffscreenLayer = false;
for (IPCRenderBufferOp* op = buffer->getOps(); op; op = op->next) {
if constexpr (DUMP_OPS) {
ALOGE("Rendering op %s", opTypeToString(op->type).c_str());
ALOGE("Details %s", opToString(op).c_str());
}
if (op->type == TYPE_BEGINRENDERTARGET) {
if (boundSurface) {
if constexpr (DUMP_OPS) {
ALOGE("Nesting BeginRenderTargetOp is not supported");
}
return false;
}
renderingOffscreenLayer = true;
if (cache) {
BeginRenderTargetOp* co = (BeginRenderTargetOp*)op;
auto it = cache->bitmaps.find(co->bufferId);
if (it != cache->bitmaps.end()) {
boundSurface = it->second.surface;
} else {
if constexpr (DUMP_OPS) {
ALOGE("Failed to acquire buffer surface for %" PRIu64, co->bufferId);
}
return false;
}
} else {
if constexpr (DUMP_OPS) {
ALOGE("IPC cache is null, BeginRenderTargetOp requires a non-null cache");
}
return false;
}
} else if (op->type == TYPE_ENDRENDERTARGET) {
renderingOffscreenLayer = false;
if (!boundSurface) {
if constexpr (DUMP_OPS) {
ALOGE("Encountered EndRenderTargetOp but no BeginRenderTargetOp was "
"submitted");
}
return false;
}
boundSurface = nullptr;
} else {
// TODO(b/485930305): Effectively every layer comes with a clear
// at the beginning. We skip this as it's not useful (e.g. it will)
// end up clearing whatever is underneath in the OOPR case. However
// it would be better to just not omit it on the client side.
if (!renderingOffscreenLayer && !foundFirstDrawingOp) {
if (isDrawingOp(op->type)) {
foundFirstDrawingOp = true;
}
if (isClear(op)) {
continue;
}
}
SkMatrix initialMatrix;
SkRect initialClip;
if (boundSurface) {
initialMatrix = SkMatrix::I();
initialClip = SkRect::MakeWH(boundSurface->width(), boundSurface->height());
} else {
initialMatrix = rootMatrix;
initialClip = rootClip;
}
renderOpToCanvas(cache, buffer, op, boundSurface ? boundSurface->getCanvas() : canvas,
renderProxyCallback, initialMatrix, initialClip);
}
}
if constexpr (DUMP_OPS) {
ALOGE("Done rendering command buffer");
}
return true;
}
bool toShmemPaint(RenderCommandBuffer* buffer, const SkPaint& paint, ShmemPaint& outPaint,
IPCClientResourceCache* clientCache) {
SkSerialProcs procs;
procs.fImageCtx = clientCache;
procs.fImageProc = [](SkImage* img, void* ctx) -> sk_sp<const SkData> {
uint64_t bufferId = 0;
if (ctx) {
auto* cache = static_cast<IPCClientResourceCache*>(ctx);
auto it = cache->bitmaps.find(img->uniqueID());
if (it != cache->bitmaps.end()) {
bufferId = it->second.id;
}
}
return SkData::MakeWithCopy(&bufferId, sizeof(bufferId));
};
SkBinaryWriteBuffer writer(procs);
SkPaintPriv::Flatten(paint, writer);
sk_sp<SkData> data = writer.snapshotAsData();
if (!SetRSpan(outPaint.data, buffer, (const uint8_t*)nullptr, data->size())) {
return false;
}
if (data->size() > 0) {
memcpy(outPaint.data.data.get(), data->data(), data->size());
}
return true;
}
std::string shmemPaintToString(const ShmemPaint& paint) {
return std::string("ShmemPaint(size=") + std::to_string(paint.data.size) + ")";
}
#define OP_REQUIRE(expr) \
({ \
if (!(expr)) { \
ALOGE("%s:%s:%d: Expression was false: %s", __FILE__, __func__, __LINE__, #expr); \
return nullptr; \
} \
})
SaveOp* SaveOp::Create(RenderCommandBuffer* commandBuffer) {
SaveOp* op = commandBuffer->allocAligned<SaveOp>();
OP_REQUIRE(op);
op->type = kType;
return op;
}
void SaveOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->save();
}
std::string SaveOp::toString() const {
return std::string("SaveOp");
}
RestoreOp* RestoreOp::Create(RenderCommandBuffer* commandBuffer) {
RestoreOp* op = commandBuffer->allocAligned<RestoreOp>();
OP_REQUIRE(op);
op->type = kType;
return op;
}
void RestoreOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->restore();
}
std::string RestoreOp::toString() const {
return std::string("RestoreOp");
}
SaveLayerOp* SaveLayerOp::Create(RenderCommandBuffer* commandBuffer, const SkRect* bounds,
const SkPaint* paint, IPCClientResourceCache* clientCache) {
SaveLayerOp* op = commandBuffer->allocAligned<SaveLayerOp>();
OP_REQUIRE(op);
op->type = kType;
if (bounds) {
op->bounds = *bounds;
op->hasBounds = true;
} else {
op->hasBounds = false;
}
if (paint) {
OP_REQUIRE(toShmemPaint(commandBuffer, *paint, op->paint, clientCache));
op->hasPaint = true;
} else {
op->hasPaint = false;
}
return op;
}
void SaveLayerOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
const SkRect* boundsPtr = hasBounds ? &bounds : nullptr;
SkPaint p;
const SkPaint* paintPtr = hasPaint ? &(p = fromShmemPaint(paint, serverCache)) : nullptr;
c->saveLayer(boundsPtr, paintPtr);
}
std::string SaveLayerOp::toString() const {
return std::string("SaveLayerOp");
}
SaveBehindOp* SaveBehindOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& subset) {
SaveBehindOp* op = commandBuffer->allocAligned<SaveBehindOp>();
OP_REQUIRE(op);
op->type = kType;
if (subset.isEmpty()) {
op->subset.setEmpty();
} else {
op->subset = subset;
}
return op;
}
void SaveBehindOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
SkAndroidFrameworkUtils::SaveBehind(c, &subset);
}
std::string SaveBehindOp::toString() const {
return std::string("SaveBehindOp subset: ") + rectToString(subset);
}
ConcatOp* ConcatOp::Create(RenderCommandBuffer* commandBuffer, const SkM44& matrix) {
ConcatOp* op = commandBuffer->allocAligned<ConcatOp>();
OP_REQUIRE(op);
op->type = kType;
op->matrix = matrix;
return op;
}
void ConcatOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->concat(matrix);
}
std::string ConcatOp::toString() const {
return std::string("ConcatOp matrix: ") + skmatrixToString(matrix);
}
SetMatrixOp* SetMatrixOp::Create(RenderCommandBuffer* commandBuffer, const SkM44& matrix) {
SetMatrixOp* op = commandBuffer->allocAligned<SetMatrixOp>();
OP_REQUIRE(op);
op->type = kType;
op->matrix = matrix;
return op;
}
void SetMatrixOp::draw(SkCanvas* c, const SkMatrix& original, IPCServerResourceCache* serverCache) {
c->setMatrix(SkM44(original) * matrix);
}
std::string SetMatrixOp::toString() const {
return std::string("SetMatrixOp matrix: ") + skmatrixToString(matrix);
}
ScaleOp* ScaleOp::Create(RenderCommandBuffer* commandBuffer, SkScalar sx, SkScalar sy) {
ScaleOp* op = commandBuffer->allocAligned<ScaleOp>();
OP_REQUIRE(op);
op->type = kType;
op->sx = sx;
op->sy = sy;
return op;
}
void ScaleOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->scale(sx, sy);
}
std::string ScaleOp::toString() const {
return std::string("ScaleOp sx: ") + std::to_string(sx) + std::string(" sy: ") +
std::to_string(sy);
}
TranslateOp* TranslateOp::Create(RenderCommandBuffer* commandBuffer, SkScalar dx, SkScalar dy) {
TranslateOp* op = commandBuffer->allocAligned<TranslateOp>();
OP_REQUIRE(op);
op->type = kType;
op->dx = dx;
op->dy = dy;
return op;
}
void TranslateOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->translate(dx, dy);
}
std::string TranslateOp::toString() const {
return std::string("TranslateOp dx: ") + std::to_string(dx) + std::string(" dy: ") +
std::to_string(dy);
}
ClipPathOp* ClipPathOp::Create(RenderCommandBuffer* commandBuffer, const SkPath& path, SkClipOp op,
bool aa) {
ClipPathOp* opData = commandBuffer->allocAligned<ClipPathOp>();
OP_REQUIRE(opData);
size_t pathSize = path.writeToMemory(nullptr);
OP_REQUIRE(SetRSpan<uint8_t>(opData->pathData, commandBuffer, nullptr, pathSize));
path.writeToMemory(opData->pathData.data.get());
opData->type = kType;
opData->op = op;
opData->aa = aa;
return opData;
}
void ClipPathOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
const SkPath path =
SkPath::ReadFromMemory(pathData.data.get(), pathData.size).value_or(SkPath());
c->clipPath(path, op, aa);
}
std::string ClipPathOp::toString() const {
return "ClipPathOp";
}
ClipRectOp* ClipRectOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& rect, SkClipOp op,
bool aa) {
ClipRectOp* opData = commandBuffer->allocAligned<ClipRectOp>();
OP_REQUIRE(opData);
opData->type = kType;
opData->rect = rect;
opData->op = op;
opData->aa = aa;
return opData;
}
void ClipRectOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->clipRect(rect, op, aa);
}
std::string ClipRectOp::toString() const {
return std::string("ClipRectOp: rect: ") + rectToString(rect) + std::string(" op: ") +
std::to_string((int)op) + std::string(" aa: ") + std::to_string(aa);
}
ClipRRectOp* ClipRRectOp::Create(RenderCommandBuffer* commandBuffer, const SkRRect& rrect,
SkClipOp op, bool aa) {
ClipRRectOp* opData = commandBuffer->allocAligned<ClipRRectOp>();
OP_REQUIRE(opData);
opData->type = kType;
opData->rrect = rrect;
opData->op = op;
opData->aa = aa;
return opData;
}
void ClipRRectOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->clipRRect(rrect, op, aa);
}
std::string ClipRRectOp::toString() const {
std::string rectAsString = std::string(rrect.dumpToString(false).c_str());
return std::string("ClipRRectOp: rrect: ") + rectAsString + std::string(" op: ") +
std::to_string((int)op) + std::string(" aa: ") + std::to_string(aa);
}
ClipRegionOp* ClipRegionOp::Create(RenderCommandBuffer* commandBuffer, const SkRegion& region,
SkClipOp op) {
IPCRENDERBUFFER_UNIMPLEMENTED;
return nullptr;
}
void ClipRegionOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
SkRegion region;
region.readFromMemory(regionData.data.get(), regionData.size);
c->clipRegion(region, op);
}
std::string ClipRegionOp::toString() const {
return "ClipRegionOp";
}
ClipShaderOp* ClipShaderOp::Create(RenderCommandBuffer* commandBuffer,
const sk_sp<SkShader>& /*shader*/, SkClipOp op) {
IPCRENDERBUFFER_UNIMPLEMENTED;
return nullptr;
}
void ClipShaderOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string ClipShaderOp::toString() const {
return "ClipShaderOp";
}
ResetClipOp* ResetClipOp::Create(RenderCommandBuffer* commandBuffer) {
ResetClipOp* op = commandBuffer->allocAligned<ResetClipOp>();
OP_REQUIRE(op);
op->type = kType;
return op;
}
void ResetClipOp::draw(SkCanvas* c, const SkMatrix&, const SkRect& initialClip,
IPCServerResourceCache* serverCache) {
SkAndroidFrameworkUtils::ResetClip(c);
if (!initialClip.isEmpty()) {
SkMatrix ctm = c->getTotalMatrix();
c->setMatrix(SkMatrix::I());
c->clipRect(initialClip, SkClipOp::kIntersect, false);
c->setMatrix(ctm);
}
}
std::string ResetClipOp::toString() const {
return "ResetClipOp";
}
DrawPaintOp* DrawPaintOp::Create(RenderCommandBuffer* commandBuffer, const SkPaint& p,
IPCClientResourceCache* clientCache) {
DrawPaintOp* op = commandBuffer->allocAligned<DrawPaintOp>();
OP_REQUIRE(op);
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawPaintOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawPaint(fromShmemPaint(paint, serverCache));
}
std::string DrawPaintOp::toString() const {
return "DrawPaintOp" + shmemPaintToString(paint);
}
DrawBehindOp* DrawBehindOp::Create(RenderCommandBuffer* commandBuffer, const SkPaint& p,
IPCClientResourceCache* clientCache) {
DrawBehindOp* op = commandBuffer->allocAligned<DrawBehindOp>();
OP_REQUIRE(op);
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawBehindOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawBehindOp::toString() const {
return "DrawBehindOp";
}
DrawPathOp* DrawPathOp::Create(RenderCommandBuffer* commandBuffer, const SkPath& path,
const SkPaint& p, IPCClientResourceCache* clientCache) {
DrawPathOp* op = commandBuffer->allocAligned<DrawPathOp>();
OP_REQUIRE(op);
size_t pathSize = path.writeToMemory(nullptr);
OP_REQUIRE(SetRSpan<uint8_t>(op->pathData, commandBuffer, nullptr, pathSize));
path.writeToMemory(op->pathData.data.get());
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawPathOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
const SkPath path =
SkPath::ReadFromMemory(pathData.data.get(), pathData.size).value_or(SkPath());
c->drawPath(path, fromShmemPaint(paint, serverCache));
}
std::string DrawPathOp::toString() const {
return "DrawPathOp";
}
DrawRectOp* DrawRectOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& r,
const SkPaint& p, IPCClientResourceCache* clientCache) {
DrawRectOp* op = commandBuffer->allocAligned<DrawRectOp>();
OP_REQUIRE(op);
op->rect = r;
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawRectOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawRect(rect, fromShmemPaint(paint, serverCache));
}
std::string DrawRectOp::toString() const {
return std::string("DrawRectOp rect(") + rectToString(rect) + ") " + std::string(" paint: ") +
shmemPaintToString(paint);
}
DrawRegionOp* DrawRegionOp::Create(RenderCommandBuffer* commandBuffer, const SkRegion& r,
const SkPaint& p, IPCClientResourceCache* clientCache) {
DrawRegionOp* op = commandBuffer->allocAligned<DrawRegionOp>();
OP_REQUIRE(op);
size_t regionSize = r.writeToMemory(nullptr);
OP_REQUIRE(SetRSpan<uint8_t>(op->regionData, commandBuffer, nullptr, regionSize));
r.writeToMemory(op->regionData.data.get());
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawRegionOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
SkRegion region;
region.readFromMemory(regionData.data.get(), regionData.size);
c->drawRegion(region, fromShmemPaint(paint, serverCache));
}
std::string DrawRegionOp::toString() const {
return "DrawRegionOp";
}
DrawOvalOp* DrawOvalOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& o,
const SkPaint& p, IPCClientResourceCache* clientCache) {
DrawOvalOp* op = commandBuffer->allocAligned<DrawOvalOp>();
OP_REQUIRE(op);
op->oval = o;
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->type = kType;
return op;
}
void DrawOvalOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawOval(oval, fromShmemPaint(paint, serverCache));
}
std::string DrawOvalOp::toString() const {
return std::string("DrawOvalOp") + rectToString(oval);
}
DrawArcOp* DrawArcOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& oval,
SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
const SkPaint& paint, IPCClientResourceCache* clientCache) {
DrawArcOp* op = commandBuffer->allocAligned<DrawArcOp>();
OP_REQUIRE(op);
op->type = kType;
OP_REQUIRE(toShmemPaint(commandBuffer, paint, op->paint, clientCache));
op->oval = oval;
op->startAngle = startAngle;
op->sweepAngle = sweepAngle;
op->useCenter = useCenter;
return op;
}
void DrawArcOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawArc(oval, startAngle, sweepAngle, useCenter, fromShmemPaint(paint, serverCache));
}
std::string DrawArcOp::toString() const {
return std::string("DrawArcOp") + rectToString(oval) + std::string(" startAngle: ") +
std::to_string(startAngle) + std::string(" sweepAngle: ") + std::to_string(sweepAngle) +
std::string(" useCenter: ") + std::to_string(useCenter);
}
DrawRRectOp* DrawRRectOp::Create(RenderCommandBuffer* commandBuffer, const SkRRect& rr,
const SkPaint& p, IPCClientResourceCache* clientCache) {
DrawRRectOp* op = commandBuffer->allocAligned<DrawRRectOp>();
OP_REQUIRE(op);
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, clientCache));
op->rrect = rr;
op->type = kType;
return op;
}
void DrawRRectOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawRRect(rrect, fromShmemPaint(paint, serverCache));
}
std::string DrawRRectOp::toString() const {
return std::string("DrawRRectOp") + std::string(rrect.dumpToString(false).c_str());
}
DrawAnnotationOp* DrawAnnotationOp::Create(RenderCommandBuffer* commandBuffer, const SkRect& rect,
const char* text, SkData* data) {
DrawAnnotationOp* op = commandBuffer->allocAligned<DrawAnnotationOp>();
OP_REQUIRE(op);
IPCRENDERBUFFER_UNIMPLEMENTED;
op->type = kType;
return op;
}
void DrawAnnotationOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawAnnotationOp::toString() const {
return "DrawAnnotationOp";
}
DrawDrawableOp* DrawDrawableOp::Create(RenderCommandBuffer* commandBuffer, SkDrawable* drawable,
const SkMatrix* matrix) {
DrawDrawableOp* op = commandBuffer->allocAligned<DrawDrawableOp>();
OP_REQUIRE(op);
IPCRENDERBUFFER_UNIMPLEMENTED;
op->type = kType;
return op;
}
void DrawDrawableOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawDrawableOp::toString() const {
return "DrawDrawableOp";
}
DrawPictureOp* DrawPictureOp::Create(RenderCommandBuffer* commandBuffer, const SkPicture* picture,
const SkMatrix* matrix, const SkPaint* paint) {
DrawPictureOp* op = commandBuffer->allocAligned<DrawPictureOp>();
OP_REQUIRE(op);
IPCRENDERBUFFER_UNIMPLEMENTED;
op->type = kType;
return op;
}
void DrawPictureOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawPictureOp::toString() const {
return "DrawPictureOp";
}
DrawImageOp* DrawImageOp::Create(RenderCommandBuffer* commandBuffer, uint64_t bitmapId, SkScalar x,
SkScalar y, const SkSamplingOptions& sampling,
const SkPaint* paint, IPCClientResourceCache* clientCache) {
// SkCanvas::drawImage uses ImageRectOp
IPCRENDERBUFFER_UNIMPLEMENTED;
return nullptr;
}
void DrawImageOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
// SkCanvas::drawImage uses ImageRectOp
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawImageOp::toString() const {
return "DrawImageOp";
}
DrawImageRectOp* DrawImageRectOp::Create(RenderCommandBuffer* commandBuffer, uint64_t bitmapId,
const SkRect& src, const SkRect& dst,
const SkSamplingOptions& sampling, const SkPaint* paint,
SkCanvas::SrcRectConstraint constraint) {
DrawImageRectOp* op = commandBuffer->allocAligned<DrawImageRectOp>();
OP_REQUIRE(op);
op->type = kType;
op->bitmapId = bitmapId;
op->src = src;
op->dst = dst;
op->sampling = sampling;
if (paint) {
OP_REQUIRE(toShmemPaint(commandBuffer, *paint, op->paint, nullptr)); // FIXME: no cache
op->hasPaint = true;
} else {
op->hasPaint = false;
}
op->constraint = constraint;
return op;
}
void DrawImageRectOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
auto it = serverCache->bitmaps.find(bitmapId);
if (it == serverCache->bitmaps.end()) {
// This currently only happens when a process shuts down.
// There may be a frame remaining that references bitmaps which were destroyed.
ALOGE("Bitmap not found in cache id=%" PRIu64, bitmapId);
return;
}
SkPaint p;
const SkPaint* paintPtr = hasPaint ? &(p = fromShmemPaint(paint, serverCache)) : nullptr;
c->drawImageRect(it->second.image, src, dst, sampling, paintPtr, constraint);
}
std::string DrawImageRectOp::toString() const {
return "DrawImageRectOp";
}
struct SerializeTypefaceContext {
RenderCommandBuffer* commandBuffer;
IPCClientResourceCache* cache;
};
SkSerialReturnType serializeTypeFace(SkTypeface* tf, void* ctx) {
SerializeTypefaceContext* stc = reinterpret_cast<SerializeTypefaceContext*>(ctx);
RenderCommandBuffer* commandBuffer = stc->commandBuffer;
IPCClientResourceCache* cache = stc->cache;
uint32_t id = tf->uniqueID();
if (cache && cache->typefaces.count(id) == 0) {
cache->typefaces.insert(id);
auto data = tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
if (data) {
UploadTypeface::Create(commandBuffer->mRegion.get(), id, data.get());
}
}
return SkData::MakeWithCopy(&id, sizeof(id));
}
sk_sp<SkTypeface> deserializeTypeFace(SkStream& stream, void* ctx) {
auto* cache = reinterpret_cast<IPCServerResourceCache*>(ctx);
if (!cache) {
ALOGE("Trying to draw text with no resource cache!");
return nullptr;
}
uint32_t id;
if (stream.read(&id, sizeof(id)) != sizeof(id)) {
return nullptr;
}
auto it = cache->typefaces.find(id);
if (it != cache->typefaces.end()) {
return it->second;
}
ALOGE("Typeface id %u expected to be cached but not found", id);
return nullptr;
}
DrawTextBlobOp* DrawTextBlobOp::Create(RenderCommandBuffer* commandBuffer, const SkTextBlob* blob,
SkScalar x_in, SkScalar y_in, const SkPaint& p,
IPCClientResourceCache* cache) {
SkSerialProcs procs;
DrawTextBlobOp* op = commandBuffer->allocAligned<DrawTextBlobOp>();
OP_REQUIRE(op);
op->type = kType;
OP_REQUIRE(toShmemPaint(commandBuffer, p, op->paint, cache));
op->x = x_in;
op->y = y_in;
SerializeTypefaceContext ctx = {commandBuffer, cache};
procs.fTypefaceCtx = &ctx;
procs.fTypefaceProc = serializeTypeFace;
auto data = blob->serialize(procs);
OP_REQUIRE(data);
OP_REQUIRE(SetRSpan<uint8_t>(op->blobData, commandBuffer, (const uint8_t*)data->data(),
data->size()));
return op;
}
void DrawTextBlobOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
SkDeserialProcs procs;
procs.fTypefaceCtx = serverCache;
procs.fTypefaceStreamProc = deserializeTypeFace;
sk_sp<SkTextBlob> blob = SkTextBlob::Deserialize(blobData.data.get(), blobData.size, procs);
if (blob) {
c->drawTextBlob(blob, x, y, fromShmemPaint(paint, serverCache));
} else {
ALOGE("Failed to deserialize text blob");
}
}
std::string DrawTextBlobOp::toString() const {
return "DrawTextBlobOp";
}
DrawPatchOp* DrawPatchOp::Create(RenderCommandBuffer* commandBuffer, const SkPoint inPoints[12],
const SkColor inColors[4], const SkPoint inTexCoords[4],
SkBlendMode inMode, const SkPaint& inPaint,
IPCClientResourceCache* clientCache) {
DrawPatchOp* op = commandBuffer->allocAligned<DrawPatchOp>();
OP_REQUIRE(op);
op->type = kType;
op->mode = inMode;
OP_REQUIRE(toShmemPaint(commandBuffer, inPaint, op->paint, clientCache));
OP_REQUIRE(SetRSpan(op->points, commandBuffer, inPoints, 12));
OP_REQUIRE(SetRSpan(op->colors, commandBuffer, inColors, 4));
OP_REQUIRE(SetRSpan(op->texCoords, commandBuffer, inTexCoords, 4));
return op;
}
void DrawPatchOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawPatch(points.data.get(), colors.data.get(), texCoords.data.get(), mode,
fromShmemPaint(paint, serverCache));
}
std::string DrawPatchOp::toString() const {
return "DrawPatchOp";
}
DrawPointsOp* DrawPointsOp::Create(RenderCommandBuffer* commandBuffer, SkCanvas::PointMode mode,
size_t count, const SkPoint* points, const SkPaint& paint,
IPCClientResourceCache* clientCache) {
DrawPointsOp* op = commandBuffer->allocAligned<DrawPointsOp>();
OP_REQUIRE(op);
op->type = kType;
op->mode = mode;
OP_REQUIRE(toShmemPaint(commandBuffer, paint, op->paint, clientCache));
OP_REQUIRE(SetRSpan(op->points, commandBuffer, points, count));
return op;
}
void DrawPointsOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
c->drawPoints(mode, {points.data.get(), points.size}, fromShmemPaint(paint, serverCache));
}
std::string DrawPointsOp::toString() const {
return "DrawPointsOp";
}
DrawVerticesOp* DrawVerticesOp::Create(RenderCommandBuffer* commandBuffer,
const SkVertices* vertices, SkBlendMode mode,
const SkPaint& paint, IPCClientResourceCache* clientCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
return nullptr;
#if 0
DrawVerticesOp* op = commandBuffer->allocAligned<DrawVerticesOp>();
OP_REQUIRE(op);
op->type = kType;
op->mode = mode;
OP_REQUIRE(toShmemPaint(commandBuffer, paint, op->paint, clientCache));
SkBinaryWriteBuffer writeBuffer(SkSerialProcs{});
vertices->priv().encode(writeBuffer);
auto data = writeBuffer.snapshotAsData();
OP_REQUIRE(SetRSpan<uint8_t>(op->verticesData, commandBuffer,
reinterpret_cast<const uint8_t*>(data->data()), data->size()));
return op;
#endif
}
void DrawVerticesOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
#if 0
SkReadBuffer readBuffer(verticesData.data.get(), verticesData.size);
sk_sp<SkVertices> vertices = SkVerticesPriv::Decode(readBuffer);
if (vertices) {
c->drawVertices(vertices, mode, fromShmemPaint(paint, serverCache));
}
#endif
}
std::string DrawVerticesOp::toString() const {
return "DrawVerticesOp";
}
/*struct DrawMeshOp final : IPCRenderBufferOp {
const auto kType = TYPE_DRAWMESH;
DrawMeshOp(const Mesh& mesh, const SkPaint& paint) {
ALOGE("Not implemented %s", __FUNCTION__);
}
};*/
DrawSkMeshOp* DrawSkMeshOp::Create(RenderCommandBuffer* commandBuffer, const SkMesh& mesh,
sk_sp<SkBlender> blender, const SkPaint& paint,
IPCClientResourceCache* clientCache) {
DrawSkMeshOp* op = commandBuffer->allocAligned<DrawSkMeshOp>();
OP_REQUIRE(op);
op->type = kType;
IPCRENDERBUFFER_UNIMPLEMENTED;
return op;
}
void DrawSkMeshOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawSkMeshOp::toString() const {
return "DrawSkMeshOp";
}
DrawAtlasOp* DrawAtlasOp::Create(RenderCommandBuffer* commandBuffer, const SkImage* atlas,
const SkRSXform* xform, const SkRect* tex, const SkColor* colors,
int count, SkBlendMode mode, const SkSamplingOptions& sampling,
const SkRect* cull, const SkPaint* paint) {
DrawAtlasOp* op = commandBuffer->allocAligned<DrawAtlasOp>();
OP_REQUIRE(op);
IPCRENDERBUFFER_UNIMPLEMENTED;
op->type = kType;
return op;
}
void DrawAtlasOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
IPCRENDERBUFFER_UNIMPLEMENTED;
}
std::string DrawAtlasOp::toString() const {
return "DrawAtlasOp";
}
DrawProxySurfaceControlOp* DrawProxySurfaceControlOp::Create(RenderCommandBuffer* commandBuffer,
int id) {
DrawProxySurfaceControlOp* op = commandBuffer->allocAligned<DrawProxySurfaceControlOp>();
OP_REQUIRE(op);
op->type = kType;
op->proxyId = id;
return op;
}
void DrawProxySurfaceControlOp::draw(SkCanvas* c, const SkMatrix&,
IPCServerResourceCache* serverCache) {
LOG_ALWAYS_FATAL_IF("DrawProxySurfaceControlOp::draw unexpected");
}
std::string DrawProxySurfaceControlOp::toString() const {
return "DrawProxySurfaceControlOp";
}
BeginRenderTargetOp* BeginRenderTargetOp::Create(RenderCommandBuffer* commandBuffer,
uint64_t bufferId) {
BeginRenderTargetOp* op = commandBuffer->allocAligned<BeginRenderTargetOp>();
OP_REQUIRE(op);
op->type = kType;
op->bufferId = bufferId;
return op;
}
void BeginRenderTargetOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {}
std::string BeginRenderTargetOp::toString() const {
return "BeginRenderTargetOp";
}
EndRenderTargetOp* EndRenderTargetOp::Create(RenderCommandBuffer* commandBuffer) {
EndRenderTargetOp* op = commandBuffer->allocAligned<EndRenderTargetOp>();
OP_REQUIRE(op);
op->type = kType;
return op;
}
void EndRenderTargetOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {}
std::string EndRenderTargetOp::toString() const {
return "EndRenderTargetOp";
}
UploadBitmap* UploadBitmap::Create(IpcRenderRegion* region, uint64_t imageId,
const SkBitmap& bitmap) {
UploadBitmap* op = region->mUploadBuf.reserve<UploadBitmap>();
OP_REQUIRE(op);
op->type = TYPE_UPLOADBITMAP;
op->imageId = imageId;
op->width = bitmap.width();
op->height = bitmap.height();
op->colorType = (int32_t)bitmap.colorType();
op->alphaType = (int32_t)bitmap.alphaType();
op->rowBytes = bitmap.rowBytes();
size_t pixelSize = bitmap.computeByteSize();
OP_REQUIRE(SetRSpan(op->pixels, region, (const uint8_t*)bitmap.getPixels(), pixelSize));
region->mUploadBuf.commit();
return op;
}
void UploadBitmap::execute(IPCServerResourceCache& resourceCache) {
SkImageInfo info =
SkImageInfo::Make(width, height, (SkColorType)colorType, (SkAlphaType)alphaType);
if (pixels.data.get()) {
SkBitmap bitmap;
if (bitmap.tryAllocPixels(info, rowBytes)) {
memcpy(bitmap.getPixels(), pixels.data.get(), pixels.size);
bitmap.setImmutable();
sk_sp<SkImage> image = SkImages::RasterFromBitmap(bitmap);
resourceCache.bitmaps[imageId] = {nullptr, image, nullptr};
} else {
ALOGE("Failed to allocate pixels for UploadBitmap");
}
}
}
std::string UploadBitmap::toString() const {
return std::string("UploadBitmap id=") + std::to_string(imageId) + std::string(" w=") +
std::to_string(width) + std::string(" h=") + std::to_string(height) +
std::string(" ct=") + std::to_string(colorType) + std::string(" at=") +
std::to_string(alphaType) + std::string(" rb=") + std::to_string(rowBytes) +
std::string(" sz=") + std::to_string(pixels.size);
}
FreeBitmap* FreeBitmap::Create(IpcRenderRegion* region, uint64_t imageId) {
FreeBitmap* op = region->mUploadBuf.reserve<FreeBitmap>();
OP_REQUIRE(op);
op->type = TYPE_FREEBITMAP;
op->imageId = imageId;
region->mUploadBuf.commit();
return op;
}
void FreeBitmap::execute(IPCServerResourceCache& resourceCache) {
resourceCache.bitmaps.erase(imageId);
}
std::string FreeBitmap::toString() const {
return std::string("FreeBitmap id=") + std::to_string(imageId);
}
UploadTypeface* UploadTypeface::Create(IpcRenderRegion* region, uint32_t fontId,
const SkData* data) {
UploadTypeface* op = region->mUploadBuf.reserve<UploadTypeface>();
OP_REQUIRE(op);
op->type = TYPE_UPLOADTYPEFACE;
op->fontId = fontId;
OP_REQUIRE(SetRSpan(op->data, region, (const uint8_t*)data->data(), data->size()));
region->mUploadBuf.commit();
return op;
}
void UploadTypeface::execute(IPCServerResourceCache& resourceCache) {
if (data.data.get() && data.size > 0) {
SkMemoryStream stream(data.data.get(), data.size);
sk_sp<SkTypeface> tf = SkTypeface::MakeDeserialize(&stream, nullptr);
if (tf) {
resourceCache.typefaces[fontId] = tf;
} else {
ALOGE("Failed to deserialize Typeface for font id %u", fontId);
}
}
}
std::string UploadTypeface::toString() const {
return std::string("UploadTypeface id=") + std::to_string(fontId) + std::string(" size=") +
std::to_string(data.size);
}
DrawShadowRecOp* DrawShadowRecOp::Create(RenderCommandBuffer* commandBuffer, const SkPath& path,
const SkDrawShadowRec& rec) {
DrawShadowRecOp* op = commandBuffer->allocAligned<DrawShadowRecOp>();
OP_REQUIRE(op);
size_t pathSize = path.writeToMemory(nullptr);
OP_REQUIRE(SetRSpan<uint8_t>(op->pathData, commandBuffer, nullptr, pathSize));
path.writeToMemory(op->pathData.data.get());
op->rec = rec;
op->type = kType;
return op;
}
void DrawShadowRecOp::draw(SkCanvas* c, const SkMatrix&, IPCServerResourceCache* serverCache) {
const SkPath path =
SkPath::ReadFromMemory(pathData.data.get(), pathData.size).value_or(SkPath());
c->private_draw_shadow_rec(path, rec);
}
std::string DrawShadowRecOp::toString() const {
return "DrawShadowRecOp";
}
} // namespace android
#pragma clang diagnostic pop