Commit d2b1fb18 authored by Thiabaud Engelbrecht's avatar Thiabaud Engelbrecht Committed by Chromium LUCI CQ

[blink] Move SkRWBuffer to blink from skia.

This is not used anywhere in skia, so we are adding it to blink. Another
CL deletes this from skia.

This code was originally called SkRWBuffer, and was written by reed@.

The only semantic changes to this code made here is disallowing copying
and assigning of RWBuffer, neither of which happens in blink.

Bug: 1151405
Change-Id: I035b53f8bc8ab0829bce9bb73c46a5dd95ca65ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2551847
Commit-Queue: Thiabaud Engelbrecht <thiabaud@google.com>
Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Reviewed-by: default avatarMike Reed <reed@google.com>
Cr-Commit-Position: refs/heads/master@{#832682}
parent 9579fa45
......@@ -1108,6 +1108,8 @@ component("platform") {
"graphics/raster_dark_mode_filter_impl.h",
"graphics/replaying_canvas.cc",
"graphics/replaying_canvas.h",
"graphics/rw_buffer.cc",
"graphics/rw_buffer.h",
"graphics/scoped_interpolation_quality.h",
"graphics/scrollbar_theme_settings.cc",
"graphics/scrollbar_theme_settings.h",
......@@ -2017,6 +2019,7 @@ source_set("blink_platform_unittests_sources") {
"graphics/path_test.cc",
"graphics/placeholder_image_test.cc",
"graphics/raster_dark_mode_filter_impl_test.cc",
"graphics/rw_buffer_test.cc",
"graphics/video_frame_submitter_test.cc",
"heap_observer_set_test.cc",
"image-decoders/bmp/bmp_image_decoder_test.cc",
......
......@@ -77,4 +77,7 @@ specific_include_rules = {
"graphics_context.h": [
"+third_party/blink/public/mojom/frame/frame_owner_properties.mojom-blink.h",
],
"rw_buffer_test.cc": [
"+base/threading/platform_thread.h",
],
}
......@@ -190,9 +190,9 @@ sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator() {
DCHECK_GT(decoded_size.width(), 0);
DCHECK_GT(decoded_size.height(), 0);
sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
sk_sp<ROBuffer> ro_buffer(rw_buffer_->MakeROBufferSnapshot());
scoped_refptr<SegmentReader> segment_reader =
SegmentReader::CreateFromSkROBuffer(std::move(ro_buffer));
SegmentReader::CreateFromROBuffer(std::move(ro_buffer));
SkImageInfo info =
SkImageInfo::MakeN32(decoded_size.width(), decoded_size.height(),
......@@ -251,12 +251,12 @@ sk_sp<PaintImageGenerator> DeferredImageDecoder::CreateGenerator() {
scoped_refptr<SharedBuffer> DeferredImageDecoder::Data() {
if (!rw_buffer_)
return nullptr;
sk_sp<SkROBuffer> ro_buffer(rw_buffer_->makeROBufferSnapshot());
sk_sp<ROBuffer> ro_buffer(rw_buffer_->MakeROBufferSnapshot());
scoped_refptr<SharedBuffer> shared_buffer = SharedBuffer::Create();
SkROBuffer::Iter it(ro_buffer.get());
ROBuffer::Iter it(ro_buffer.get());
do {
shared_buffer->Append(static_cast<const char*>(it.data()), it.size());
} while (it.next());
} while (it.Next());
return shared_buffer;
}
......@@ -279,13 +279,13 @@ void DeferredImageDecoder::SetDataInternal(scoped_refptr<SharedBuffer> data,
if (frame_generator_) {
if (!rw_buffer_)
rw_buffer_ = std::make_unique<SkRWBuffer>(data->size());
rw_buffer_ = std::make_unique<RWBuffer>(data->size());
for (auto it = data->GetIteratorAt(rw_buffer_->size()); it != data->cend();
++it) {
DCHECK_GE(data->size(), rw_buffer_->size() + it->size());
const size_t remaining = data->size() - rw_buffer_->size() - it->size();
rw_buffer_->append(it->data(), it->size(), remaining);
rw_buffer_->Append(it->data(), it->size(), remaining);
}
}
}
......
......@@ -31,13 +31,13 @@
#include "base/macros.h"
#include "third_party/blink/renderer/platform/geometry/int_size.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_image.h"
#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/skia/include/core/SkRWBuffer.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace blink {
......@@ -104,7 +104,7 @@ class PLATFORM_EXPORT DeferredImageDecoder final {
// Copy of the data that is passed in, used by deferred decoding.
// Allows creating readonly snapshots that may be read in another thread.
std::unique_ptr<SkRWBuffer> rw_buffer_;
std::unique_ptr<RWBuffer> rw_buffer_;
std::unique_ptr<ImageDecoder> metadata_decoder_;
String filename_extension_;
......@@ -141,4 +141,4 @@ class PLATFORM_EXPORT DeferredImageDecoder final {
} // namespace blink
#endif
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_DEFERRED_IMAGE_DECODER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "base/check.h"
#include "base/check_op.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/private/SkMalloc.h"
#include <algorithm>
#include <atomic>
#include <new>
namespace blink {
namespace {
// Force small chunks to be a page's worth
static const size_t kMinAllocSize = 4096;
} // namespace
struct RWBuffer::BufferBlock {
RWBuffer::BufferBlock* next_; // updated by the writer
size_t used_; // updated by the writer
const size_t capacity_;
explicit BufferBlock(size_t capacity)
: next_(nullptr), used_(0), capacity_(capacity) {}
const void* startData() const { return this + 1; }
size_t avail() const { return capacity_ - used_; }
void* avail_data() {
return reinterpret_cast<char*>(const_cast<void*>(startData())) + used_;
}
static RWBuffer::BufferBlock* Alloc(size_t length) {
size_t capacity = LengthToCapacity(length);
void* buffer = sk_malloc_throw(sizeof(RWBuffer::BufferBlock) + capacity);
return new (buffer) RWBuffer::BufferBlock(capacity);
}
// Return number of bytes actually appended. Important that we always
// completely fill this block before spilling into the next, since the reader
// uses capacity_ to know how many bytes it can read.
size_t Append(const void* src, size_t length) {
Validate();
size_t amount = std::min(avail(), length);
memcpy(avail_data(), src, amount);
used_ += amount;
Validate();
return amount;
}
// Do not call in the reader thread, since the writer may be updating used_.
// (The assertion is still true, but TSAN still may complain about its
// raciness.)
void Validate() const {
DCHECK_GT(capacity_, 0u);
DCHECK_LE(used_, capacity_);
}
private:
static size_t LengthToCapacity(size_t length) {
const size_t min_size = kMinAllocSize - sizeof(RWBuffer::BufferBlock);
return std::max(length, min_size);
}
};
struct RWBuffer::BufferHead {
mutable std::atomic<int32_t> ref_count_;
RWBuffer::BufferBlock block_;
explicit BufferHead(size_t capacity) : ref_count_(1), block_(capacity) {}
static size_t LengthToCapacity(size_t length) {
const size_t min_size = kMinAllocSize - sizeof(RWBuffer::BufferHead);
return std::max(length, min_size);
}
static RWBuffer::BufferHead* Alloc(size_t length) {
size_t capacity = LengthToCapacity(length);
size_t size = sizeof(RWBuffer::BufferHead) + capacity;
void* buffer = sk_malloc_throw(size);
return new (buffer) RWBuffer::BufferHead(capacity);
}
void ref() const {
auto old_ref_count = ref_count_.fetch_add(+1, std::memory_order_relaxed);
DCHECK_GT(old_ref_count, 0);
}
void unref() const {
// A release here acts in place of all releases we "should" have been doing
// in ref().
int32_t oldRefCnt = ref_count_.fetch_add(-1, std::memory_order_acq_rel);
DCHECK(oldRefCnt);
if (1 == oldRefCnt) {
// Like unique(), the acquire is only needed on success.
RWBuffer::BufferBlock* block = block_.next_;
sk_free(reinterpret_cast<void*>(const_cast<RWBuffer::BufferHead*>(this)));
while (block) {
RWBuffer::BufferBlock* next = block->next_;
sk_free(block);
block = next;
}
}
}
void Validate(size_t minUsed,
const RWBuffer::BufferBlock* tail = nullptr) const {
#if DCHECK_IS_ON()
DCHECK_GT(ref_count_.load(std::memory_order_relaxed), 0);
size_t totalUsed = 0;
const RWBuffer::BufferBlock* block = &block_;
const RWBuffer::BufferBlock* lastBlock = block;
while (block) {
block->Validate();
totalUsed += block->used_;
lastBlock = block;
block = block->next_;
}
DCHECK(minUsed <= totalUsed);
if (tail) {
DCHECK(tail == lastBlock);
}
#endif
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// The reader can only access block.capacity_ (which never changes), and cannot
// access block.used_, which may be updated by the writer.
//
ROBuffer::ROBuffer(const RWBuffer::BufferHead* head,
size_t available,
const RWBuffer::BufferBlock* tail)
: head_(head), available_(available), tail_(tail) {
if (head) {
head_->ref();
DCHECK_GT(available, 0u);
head->Validate(available, tail);
} else {
DCHECK_EQ(0u, available);
DCHECK(!tail);
}
}
ROBuffer::~ROBuffer() {
if (head_) {
head_->unref();
}
}
ROBuffer::Iter::Iter(const ROBuffer* buffer) {
Reset(buffer);
}
ROBuffer::Iter::Iter(const sk_sp<ROBuffer>& buffer) {
Reset(buffer.get());
}
void ROBuffer::Iter::Reset(const ROBuffer* buffer) {
buffer_ = buffer;
if (buffer && buffer->head_) {
block_ = &buffer->head_->block_;
remaining_ = buffer->available_;
} else {
block_ = nullptr;
remaining_ = 0;
}
}
const void* ROBuffer::Iter::data() const {
return remaining_ ? block_->startData() : nullptr;
}
size_t ROBuffer::Iter::size() const {
if (!block_) {
return 0;
}
return std::min(block_->capacity_, remaining_);
}
bool ROBuffer::Iter::Next() {
if (remaining_) {
remaining_ -= size();
if (buffer_->tail_ == block_) {
// There are more blocks, but buffer_ does not know about them.
DCHECK_EQ(0u, remaining_);
block_ = nullptr;
} else {
block_ = block_->next_;
}
}
return remaining_ != 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
RWBuffer::RWBuffer(size_t initial_capacity) {
if (initial_capacity) {
head_ = RWBuffer::BufferHead::Alloc(initial_capacity);
tail_ = &head_->block_;
}
}
RWBuffer::~RWBuffer() {
Validate();
if (head_) {
head_->unref();
}
}
// It is important that we always completely fill the current block before
// spilling over to the next, since our reader will be using capacity_ (min'd
// against its total available) to know how many bytes to read from a given
// block.
//
void RWBuffer::Append(const void* src, size_t length, size_t reserve) {
Validate();
if (0 == length) {
return;
}
total_used_ += length;
if (!head_) {
head_ = RWBuffer::BufferHead::Alloc(length + reserve);
tail_ = &head_->block_;
}
size_t written = tail_->Append(src, length);
DCHECK(written <= length);
src = static_cast<const char*>(src) + written;
length -= written;
if (length) {
RWBuffer::BufferBlock* block =
RWBuffer::BufferBlock::Alloc(length + reserve);
tail_->next_ = block;
tail_ = block;
written = tail_->Append(src, length);
DCHECK(written == length);
}
Validate();
}
sk_sp<ROBuffer> RWBuffer::MakeROBufferSnapshot() const {
return sk_sp<ROBuffer>(new ROBuffer(head_, total_used_, tail_));
}
void RWBuffer::Validate() const {
#if DCHECK_IS_ON()
if (head_) {
head_->Validate(total_used_, tail_);
} else {
DCHECK(!tail_);
DCHECK_EQ(0u, total_used_);
}
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////
class ROBufferStreamAsset : public SkStreamAsset {
void Validate() const {
DCHECK(global_offset_ <= buffer_->size());
DCHECK(local_offset_ <= iter_.size());
DCHECK(local_offset_ <= global_offset_);
}
#if DCHECK_IS_ON()
class AutoValidate {
public:
explicit AutoValidate(ROBufferStreamAsset* stream) : stream_(stream) {
stream->Validate();
}
~AutoValidate() { stream_->Validate(); }
private:
ROBufferStreamAsset* stream_;
};
#else
class AutoValidate {
public:
explicit AutoValidate(ROBufferStreamAsset*) {}
};
#endif
public:
explicit ROBufferStreamAsset(sk_sp<ROBuffer> buffer)
: buffer_(std::move(buffer)), iter_(buffer_) {
global_offset_ = local_offset_ = 0;
}
size_t getLength() const override { return buffer_->size(); }
bool rewind() override {
AutoValidate av(this);
iter_.Reset(buffer_.get());
global_offset_ = local_offset_ = 0;
return true;
}
size_t read(void* dst, size_t request) override {
AutoValidate av(this);
size_t bytesRead = 0;
for (;;) {
size_t size = iter_.size();
DCHECK(local_offset_ <= size);
size_t avail = std::min(size - local_offset_, request - bytesRead);
if (dst) {
memcpy(dst, static_cast<const char*>(iter_.data()) + local_offset_,
avail);
dst = static_cast<char*>(dst) + avail;
}
bytesRead += avail;
local_offset_ += avail;
DCHECK(bytesRead <= request);
if (bytesRead == request) {
break;
}
// If we get here, we've exhausted the current iter
DCHECK(local_offset_ == size);
local_offset_ = 0;
if (!iter_.Next()) {
break; // ran out of data
}
}
global_offset_ += bytesRead;
DCHECK(global_offset_ <= buffer_->size());
return bytesRead;
}
bool isAtEnd() const override { return buffer_->size() == global_offset_; }
size_t getPosition() const override { return global_offset_; }
bool seek(size_t position) override {
AutoValidate av(this);
if (position < global_offset_) {
rewind();
}
(void)skip(position - global_offset_);
return true;
}
// Since this is overriding a member function we don't control, we can't
// change this type. So, disable the warning here instead.
bool move(long offset) override { // NOLINT
AutoValidate av(this);
offset += global_offset_;
if (offset <= 0) {
rewind();
} else {
(void)seek(SkToSizeT(offset));
}
return true;
}
private:
SkStreamAsset* onDuplicate() const override {
return new ROBufferStreamAsset(buffer_);
}
SkStreamAsset* onFork() const override {
auto clone = duplicate();
clone->seek(getPosition());
return clone.release();
}
sk_sp<ROBuffer> buffer_;
ROBuffer::Iter iter_;
size_t local_offset_;
size_t global_offset_;
};
std::unique_ptr<SkStreamAsset> RWBuffer::MakeStreamSnapshot() const {
return std::make_unique<ROBufferStreamAsset>(MakeROBufferSnapshot());
}
} // namespace blink
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/skia/include/core/SkRefCnt.h"
class SkStreamAsset;
namespace blink {
class ROBuffer;
/**
* Accumulates bytes of memory that are "appended" to it, growing internal
* storage as needed. The growth is done such that at any time in the writer's
* thread, an ROBuffer or StreamAsset can be snapped off (and safely passed to
* another thread). The ROBuffer/StreamAsset snapshot can see the previously
* stored bytes, but will be unaware of any future writes.
*/
class PLATFORM_EXPORT RWBuffer {
public:
struct BufferHead;
struct BufferBlock;
explicit RWBuffer(size_t initialCapacity = 0);
~RWBuffer();
RWBuffer& operator=(const RWBuffer&) = delete;
RWBuffer(const RWBuffer&) = delete;
size_t size() const { return total_used_; }
/**
* Append |length| bytes from |buffer|.
*
* If the caller knows in advance how much more data they are going to
* append, they can pass a |reserve| hint (representing the number of upcoming
* bytes *in addition* to the current append), to minimize the number of
* internal allocations.
*/
void Append(const void* buffer, size_t length, size_t reserve = 0);
sk_sp<ROBuffer> MakeROBufferSnapshot() const;
std::unique_ptr<SkStreamAsset> MakeStreamSnapshot() const;
void Validate() const;
private:
BufferHead* head_ = nullptr;
BufferBlock* tail_ = nullptr;
size_t total_used_ = 0;
};
/**
* Contains a read-only, thread-sharable block of memory. To access the memory,
* the caller must instantiate a local iterator, as the memory is stored in 1 or
* more contiguous blocks.
*/
class PLATFORM_EXPORT ROBuffer : public SkRefCnt {
public:
/**
* Return the logical length of the data owned/shared by this buffer. It may
* be stored in multiple contiguous blocks, accessible via the iterator.
*/
size_t size() const { return available_; }
class PLATFORM_EXPORT Iter {
public:
explicit Iter(const ROBuffer*);
explicit Iter(const sk_sp<ROBuffer>&);
void Reset(const ROBuffer*);
/**
* Return the current continuous block of memory, or nullptr if the
* iterator is exhausted
*/
const void* data() const;
/**
* Returns the number of bytes in the current contiguous block of memory,
* or 0 if the iterator is exhausted.
*/
size_t size() const;
/**
* Advance to the next contiguous block of memory, returning true if there
* is another block, or false if the iterator is exhausted.
*/
bool Next();
private:
const RWBuffer::BufferBlock* block_;
size_t remaining_;
const ROBuffer* buffer_;
};
private:
ROBuffer(const RWBuffer::BufferHead* head,
size_t available,
const RWBuffer::BufferBlock* tail);
~ROBuffer() override;
const RWBuffer::BufferHead* head_;
const size_t available_;
const RWBuffer::BufferBlock* tail_;
friend class RWBuffer;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_RW_BUFFER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include <array>
#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkStream.h"
namespace blink {
namespace {
const char gABC[] = "abcdefghijklmnopqrstuvwxyz";
void check_abcs(const char buffer[], size_t size) {
ASSERT_EQ(size % 26, 0u);
for (size_t offset = 0; offset < size; offset += 26) {
EXPECT_TRUE(!memcmp(&buffer[offset], gABC, 26));
}
}
// stream should contain an integral number of copies of gABC.
void check_alphabet_stream(SkStream* stream) {
ASSERT_TRUE(stream->hasLength());
size_t size = stream->getLength();
ASSERT_EQ(size % 26, 0u);
std::vector<char> storage(size);
char* array = storage.data();
size_t bytesRead = stream->read(array, size);
EXPECT_EQ(bytesRead, size);
check_abcs(array, size);
// try checking backwards
for (size_t offset = size; offset > 0; offset -= 26) {
EXPECT_TRUE(stream->seek(offset - 26));
EXPECT_EQ(stream->getPosition(), offset - 26);
EXPECT_EQ(stream->read(array, 26), 26u);
check_abcs(array, 26);
EXPECT_EQ(stream->getPosition(), offset);
}
}
// reader should contains an integral number of copies of gABC.
void check_alphabet_buffer(const ROBuffer* reader) {
size_t size = reader->size();
ASSERT_EQ(size % 26, 0u);
std::vector<char> storage(size);
ROBuffer::Iter iter(reader);
size_t offset = 0;
do {
ASSERT_LE(offset + iter.size(), size);
memcpy(storage.data() + offset, iter.data(), iter.size());
offset += iter.size();
} while (iter.Next());
ASSERT_EQ(offset, size);
check_abcs(storage.data(), size);
}
class ROBufferTestThread : public base::PlatformThread::Delegate {
public:
ROBufferTestThread(sk_sp<ROBuffer> reader, SkStream* stream, size_t i)
: reader_(reader), stream_(stream), i_(i) {}
ROBufferTestThread() = default;
ROBufferTestThread(const ROBufferTestThread&) = default;
void ThreadMain() override {
EXPECT_EQ((i_ + 1) * 26U, reader_->size());
EXPECT_EQ(stream_->getLength(), reader_->size());
check_alphabet_buffer(reader_.get());
check_alphabet_stream(stream_);
EXPECT_TRUE(stream_->rewind());
delete stream_;
}
sk_sp<ROBuffer> reader_;
SkStream* stream_;
size_t i_;
};
} // namespace
TEST(RWBuffer, reporter) {
// Knowing that the default capacity is 4096, choose N large enough so we
// force it to use multiple buffers internally.
static constexpr size_t N = 1000;
std::array<sk_sp<ROBuffer>, N> readers;
std::array<std::unique_ptr<SkStream>, N> streams;
{
RWBuffer buffer;
for (size_t i = 0; i < N; ++i) {
buffer.Append(gABC, 26);
readers[i] = buffer.MakeROBufferSnapshot();
streams[i] = buffer.MakeStreamSnapshot();
}
EXPECT_EQ(N * 26, buffer.size());
}
// Verify that although the RWBuffer's destructor has run, the readers are
// still valid.
for (size_t i = 0; i < N; ++i) {
EXPECT_EQ((i + 1) * 26U, readers[i]->size());
check_alphabet_buffer(readers[i].get());
check_alphabet_stream(streams[i].get());
}
}
TEST(RWBuffer_threaded, reporter) {
// Knowing that the default capacity is 4096, choose N large enough so we
// force it to use multiple buffers internally.
constexpr size_t N = 1000;
RWBuffer buffer;
std::array<ROBufferTestThread, N> threads;
std::array<base::PlatformThreadHandle, N> handlers;
for (size_t i = 0; i < N; ++i) {
buffer.Append(gABC, 26);
sk_sp<ROBuffer> reader = buffer.MakeROBufferSnapshot();
SkStream* stream = buffer.MakeStreamSnapshot().release();
EXPECT_EQ(reader->size(), buffer.size());
EXPECT_EQ(stream->getLength(), buffer.size());
// reader's copy constructor will ref the ROBuffer, which will be unreffed
// when the task ends.
// Ownership of stream is passed to the task, which will delete it.
threads[i] = ROBufferTestThread(reader, stream, i);
ASSERT_TRUE(base::PlatformThread::Create(0, &threads[i], &handlers[i]));
}
EXPECT_EQ(N * 26, buffer.size());
for (size_t i = 0; i < N; ++i) {
base::PlatformThread::Join(handlers[i]);
}
}
// Tests that it is safe to call ROBuffer::Iter::size() when exhausted.
TEST(RWBuffer_size, r) {
RWBuffer buffer;
buffer.Append(gABC, 26);
sk_sp<ROBuffer> roBuffer(buffer.MakeROBufferSnapshot());
ROBuffer::Iter iter(roBuffer.get());
EXPECT_TRUE(iter.data());
EXPECT_EQ(iter.size(), 26u);
// There is only one block in this buffer.
EXPECT_TRUE(!iter.Next());
EXPECT_EQ(0u, iter.size());
}
// Tests that operations (including the destructor) are safe on an RWBuffer
// without any data appended.
TEST(RWBuffer_noAppend, r) {
RWBuffer buffer;
ASSERT_EQ(0u, buffer.size());
sk_sp<ROBuffer> roBuffer = buffer.MakeROBufferSnapshot();
ASSERT_TRUE(roBuffer);
if (roBuffer) {
EXPECT_EQ(roBuffer->size(), 0u);
ROBuffer::Iter iter(roBuffer.get());
EXPECT_EQ(iter.size(), 0u);
EXPECT_TRUE(!iter.data());
EXPECT_TRUE(!iter.Next());
}
std::unique_ptr<SkStream> stream(buffer.MakeStreamSnapshot());
EXPECT_TRUE(stream);
if (stream) {
EXPECT_TRUE(stream->hasLength());
EXPECT_EQ(stream->getLength(), 0u);
EXPECT_EQ(stream->skip(10), 0u);
}
}
} // namespace blink
......@@ -29,10 +29,10 @@
*/
#include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
#include "third_party/blink/renderer/platform/image-decoders/segment_reader.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkRWBuffer.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -42,14 +42,14 @@ namespace {
scoped_refptr<SegmentReader> CopyToROBufferSegmentReader(
scoped_refptr<SegmentReader> input) {
SkRWBuffer rw_buffer;
RWBuffer rw_buffer;
const char* segment = nullptr;
size_t position = 0;
while (size_t length = input->GetSomeData(segment, position)) {
rw_buffer.append(segment, length);
rw_buffer.Append(segment, length);
position += length;
}
return SegmentReader::CreateFromSkROBuffer(rw_buffer.makeROBufferSnapshot());
return SegmentReader::CreateFromROBuffer(rw_buffer.MakeROBufferSnapshot());
}
scoped_refptr<SegmentReader> CopyToDataSegmentReader(
......@@ -60,7 +60,7 @@ scoped_refptr<SegmentReader> CopyToDataSegmentReader(
struct SegmentReaders {
scoped_refptr<SegmentReader> segment_readers[3];
SegmentReaders(scoped_refptr<SharedBuffer> input) {
explicit SegmentReaders(scoped_refptr<SharedBuffer> input) {
segment_readers[0] =
SegmentReader::CreateFromSharedBuffer(std::move(input));
segment_readers[1] = CopyToROBufferSegmentReader(segment_readers[0]);
......@@ -201,21 +201,21 @@ TEST(SegmentReaderTest, variableSegments) {
scoped_refptr<SegmentReader> segment_reader;
{
// Create a SegmentReader with difference sized segments, to test that
// the SkROBuffer implementation works when two consecutive segments
// the ROBuffer implementation works when two consecutive segments
// are not the same size. This test relies on knowledge of the
// internals of SkRWBuffer: it ensures that each segment is at least
// internals of RWBuffer: it ensures that each segment is at least
// 4096 (though the actual data may be smaller, if it has not been
// written to yet), but when appending a larger amount it may create a
// larger segment.
SkRWBuffer rw_buffer;
rw_buffer.append(reference_data, SharedBuffer::kSegmentSize);
rw_buffer.append(reference_data + SharedBuffer::kSegmentSize,
RWBuffer rw_buffer;
rw_buffer.Append(reference_data, SharedBuffer::kSegmentSize);
rw_buffer.Append(reference_data + SharedBuffer::kSegmentSize,
2 * SharedBuffer::kSegmentSize);
rw_buffer.append(reference_data + 3 * SharedBuffer::kSegmentSize,
rw_buffer.Append(reference_data + 3 * SharedBuffer::kSegmentSize,
.5 * SharedBuffer::kSegmentSize);
segment_reader =
SegmentReader::CreateFromSkROBuffer(rw_buffer.makeROBufferSnapshot());
SegmentReader::CreateFromROBuffer(rw_buffer.MakeROBufferSnapshot());
}
const char* segment;
......
......@@ -9,11 +9,11 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/graphics/rw_buffer.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkRWBuffer.h"
namespace blink {
......@@ -103,23 +103,23 @@ sk_sp<SkData> DataSegmentReader::GetAsSkData() const {
class ROBufferSegmentReader final : public SegmentReader {
public:
explicit ROBufferSegmentReader(sk_sp<SkROBuffer>);
explicit ROBufferSegmentReader(sk_sp<ROBuffer>);
size_t size() const override;
size_t GetSomeData(const char*& data, size_t position) const override;
sk_sp<SkData> GetAsSkData() const override;
private:
sk_sp<SkROBuffer> ro_buffer_;
sk_sp<ROBuffer> ro_buffer_;
mutable Mutex read_mutex_;
// Position of the first char in the current block of iter_.
mutable size_t position_of_block_ GUARDED_BY(read_mutex_);
mutable SkROBuffer::Iter iter_ GUARDED_BY(read_mutex_);
mutable ROBuffer::Iter iter_ GUARDED_BY(read_mutex_);
DISALLOW_COPY_AND_ASSIGN(ROBufferSegmentReader);
};
ROBufferSegmentReader::ROBufferSegmentReader(sk_sp<SkROBuffer> buffer)
ROBufferSegmentReader::ROBufferSegmentReader(sk_sp<ROBuffer> buffer)
: ro_buffer_(std::move(buffer)),
position_of_block_(0),
iter_(ro_buffer_.get()) {}
......@@ -136,8 +136,8 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
MutexLocker lock(read_mutex_);
if (position < position_of_block_) {
// SkROBuffer::Iter only iterates forwards. Start from the beginning.
iter_.reset(ro_buffer_.get());
// ROBuffer::Iter only iterates forwards. Start from the beginning.
iter_.Reset(ro_buffer_.get());
position_of_block_ = 0;
}
......@@ -153,9 +153,9 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
}
// Move to next block.
if (!iter_.next()) {
if (!iter_.Next()) {
// Reset to the beginning, so future calls can succeed.
iter_.reset(ro_buffer_.get());
iter_.Reset(ro_buffer_.get());
position_of_block_ = 0;
return 0;
}
......@@ -165,7 +165,7 @@ size_t ROBufferSegmentReader::GetSomeData(const char*& data,
}
static void UnrefROBuffer(const void* ptr, void* context) {
static_cast<SkROBuffer*>(context)->unref();
static_cast<ROBuffer*>(context)->unref();
}
sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
......@@ -173,9 +173,9 @@ sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
return nullptr;
// Check to see if the data is already contiguous.
SkROBuffer::Iter iter(ro_buffer_.get());
const bool multiple_blocks = iter.next();
iter.reset(ro_buffer_.get());
ROBuffer::Iter iter(ro_buffer_.get());
const bool multiple_blocks = iter.Next();
iter.Reset(ro_buffer_.get());
if (!multiple_blocks) {
// Contiguous data. No need to copy.
......@@ -190,7 +190,7 @@ sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
size_t size = iter.size();
memcpy(dst, iter.data(), size);
dst += size;
} while (iter.next());
} while (iter.Next());
return data;
}
......@@ -206,8 +206,8 @@ scoped_refptr<SegmentReader> SegmentReader::CreateFromSkData(
return base::AdoptRef(new DataSegmentReader(std::move(data)));
}
scoped_refptr<SegmentReader> SegmentReader::CreateFromSkROBuffer(
sk_sp<SkROBuffer> buffer) {
scoped_refptr<SegmentReader> SegmentReader::CreateFromROBuffer(
sk_sp<ROBuffer> buffer) {
return base::AdoptRef(new ROBufferSegmentReader(std::move(buffer)));
}
......
......@@ -12,19 +12,20 @@
#include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h"
class SkData;
class SkROBuffer;
template <typename T>
class sk_sp;
namespace blink {
class ROBuffer;
// Interface that looks like SharedBuffer. Used by ImageDecoders to use various
// sources of input including:
// - SharedBuffer
// - for when the caller already has a SharedBuffer
// - SkData
// - for when the caller already has an SkData
// - SkROBuffer
// - ROBuffer
// - for when the caller wants to read/write in different threads
//
// Unlike SharedBuffer, this is a read-only interface. There is no way to
......@@ -40,7 +41,7 @@ class PLATFORM_EXPORT SegmentReader
// These versions use thread-safe input, so they are always thread-safe.
static scoped_refptr<SegmentReader> CreateFromSkData(sk_sp<SkData>);
static scoped_refptr<SegmentReader> CreateFromSkROBuffer(sk_sp<SkROBuffer>);
static scoped_refptr<SegmentReader> CreateFromROBuffer(sk_sp<ROBuffer>);
SegmentReader() = default;
virtual ~SegmentReader() = default;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment