| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "src/text/gpu/SlugImpl.h" | |
| #include "include/core/SkMatrix.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkSerialProcs.h" | |
| #include "include/private/SkAssert.h" | |
| #include "include/private/chromium/Slug.h" | |
| #include "src/core/SkDevice.h" | |
| #include "src/core/SkReadBuffer.h" | |
| #include "src/core/SkWriteBuffer.h" | |
| #include "src/text/GlyphRun.h" | |
| #include "src/text/gpu/SubRunAllocator.h" | |
| #include "src/text/gpu/SubRunContainer.h" | |
| #include <memory> | |
| #include <utility> | |
| class SkStrikeClient; | |
| namespace sktext::gpu { | |
| SlugImpl::SlugImpl(SubRunAllocator&& alloc, | |
| gpu::SubRunContainerOwner subRuns, | |
| SkRect sourceBounds, | |
| SkPoint origin) | |
| : fAlloc {std::move(alloc)} | |
| , fSubRuns(std::move(subRuns)) | |
| , fSourceBounds{sourceBounds} | |
| , fOrigin{origin} {} | |
| void SlugImpl::doFlatten(SkWriteBuffer& buffer) const { | |
| buffer.writeRect(fSourceBounds); | |
| buffer.writePoint(fOrigin); | |
| fSubRuns->flattenAllocSizeHint(buffer); | |
| fSubRuns->flattenRuns(buffer); | |
| } | |
| sk_sp<Slug> SlugImpl::MakeFromBuffer(SkReadBuffer& buffer, const SkStrikeClient* client) { | |
| SkRect sourceBounds = buffer.readRect(); | |
| if (!buffer.validate(!sourceBounds.isEmpty())) { | |
| return nullptr; | |
| } | |
| SkPoint origin = buffer.readPoint(); | |
| int allocSizeHint = gpu::SubRunContainer::AllocSizeHintFromBuffer(buffer); | |
| auto [initializer, _, alloc] = | |
| SubRunAllocator::AllocateClassMemoryAndArena<SlugImpl>(allocSizeHint); | |
| gpu::SubRunContainerOwner container = | |
| gpu::SubRunContainer::MakeFromBufferInAlloc(buffer, client, &alloc); | |
| // Something went wrong while reading. | |
| if (!buffer.isValid()) { | |
| return nullptr; | |
| } | |
| return sk_sp<SlugImpl>( | |
| initializer.initialize(std::move(alloc), std::move(container), sourceBounds, origin)); | |
| } | |
| SkMatrix position_matrix(const SkMatrix& drawMatrix, SkPoint drawOrigin) { | |
| SkMatrix position_matrix = drawMatrix; | |
| return position_matrix.preTranslate(drawOrigin.x(), drawOrigin.y()); | |
| } | |
| sk_sp<SlugImpl> SlugImpl::Make(const SkMatrix& viewMatrix, | |
| const sktext::GlyphRunList& glyphRunList, | |
| const SkPaint& paint, | |
| SkStrikeDeviceInfo strikeDeviceInfo, | |
| sktext::StrikeForGPUCacheInterface* strikeCache) { | |
| size_t subRunSizeHint = gpu::SubRunContainer::EstimateAllocSize(glyphRunList); | |
| auto [initializer, _, alloc] = | |
| SubRunAllocator::AllocateClassMemoryAndArena<SlugImpl>(subRunSizeHint); | |
| const SkMatrix positionMatrix = position_matrix(viewMatrix, glyphRunList.origin()); | |
| auto subRuns = gpu::SubRunContainer::MakeInAlloc(glyphRunList, | |
| positionMatrix, | |
| paint, | |
| strikeDeviceInfo, | |
| strikeCache, | |
| &alloc, | |
| gpu::SubRunContainer::kAddSubRuns, | |
| "Make Slug"); | |
| sk_sp<SlugImpl> slug = sk_sp<SlugImpl>(initializer.initialize(std::move(alloc), | |
| std::move(subRuns), | |
| glyphRunList.sourceBounds(), | |
| glyphRunList.origin())); | |
| // There is nothing to draw here. This is particularly a problem with RSX form blobs where a | |
| // single space becomes a run with no glyphs. | |
| if (slug->fSubRuns->isEmpty()) { return nullptr; } | |
| return slug; | |
| } | |
| void Slug::AddDeserialProcs(SkDeserialProcs* procs, const SkStrikeClient* client) { | |
| SkASSERT(procs); | |
| procs->fSlugCtx = const_cast<SkStrikeClient*>(client); | |
| procs->fSlugProc = [](SkReadBuffer& buffer, void* ctx) -> sk_sp<Slug> { | |
| auto client = static_cast<const SkStrikeClient*>(ctx); | |
| return SlugImpl::MakeFromBuffer(buffer, client); | |
| }; | |
| } | |
| } // namespace sktext::gpu |