blob: 7f95a2734f459bfdb74f4790cc51bb2bd3fe12e3 [file] [log] [blame]
// Copyright 2016 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/image-decoders/segment_reader.h"
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/platform/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/noncopyable.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 {
// SharedBufferSegmentReader ---------------------------------------------------
// Interface for ImageDecoder to read a SharedBuffer.
class SharedBufferSegmentReader final : public SegmentReader {
WTF_MAKE_NONCOPYABLE(SharedBufferSegmentReader);
public:
SharedBufferSegmentReader(scoped_refptr<SharedBuffer>);
size_t size() const override;
size_t GetSomeData(const char*& data, size_t position) const override;
sk_sp<SkData> GetAsSkData() const override;
private:
scoped_refptr<SharedBuffer> shared_buffer_;
};
SharedBufferSegmentReader::SharedBufferSegmentReader(
scoped_refptr<SharedBuffer> buffer)
: shared_buffer_(std::move(buffer)) {}
size_t SharedBufferSegmentReader::size() const {
return shared_buffer_->size();
}
size_t SharedBufferSegmentReader::GetSomeData(const char*& data,
size_t position) const {
data = nullptr;
auto it = shared_buffer_->GetIteratorAt(position);
if (it == shared_buffer_->cend())
return 0;
data = it->data();
return it->size();
}
sk_sp<SkData> SharedBufferSegmentReader::GetAsSkData() const {
return shared_buffer_->GetAsSkData();
}
// DataSegmentReader -----------------------------------------------------------
// Interface for ImageDecoder to read an SkData.
class DataSegmentReader final : public SegmentReader {
WTF_MAKE_NONCOPYABLE(DataSegmentReader);
public:
DataSegmentReader(sk_sp<SkData>);
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<SkData> data_;
};
DataSegmentReader::DataSegmentReader(sk_sp<SkData> data)
: data_(std::move(data)) {}
size_t DataSegmentReader::size() const {
return data_->size();
}
size_t DataSegmentReader::GetSomeData(const char*& data,
size_t position) const {
if (position >= data_->size())
return 0;
data = reinterpret_cast<const char*>(data_->bytes() + position);
return data_->size() - position;
}
sk_sp<SkData> DataSegmentReader::GetAsSkData() const {
return data_;
}
// ROBufferSegmentReader -------------------------------------------------------
class ROBufferSegmentReader final : public SegmentReader {
WTF_MAKE_NONCOPYABLE(ROBufferSegmentReader);
public:
ROBufferSegmentReader(sk_sp<SkROBuffer>);
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_;
// Protects access to mutable fields.
mutable Mutex read_mutex_;
// Position of the first char in the current block of iter_.
mutable size_t position_of_block_;
mutable SkROBuffer::Iter iter_;
};
ROBufferSegmentReader::ROBufferSegmentReader(sk_sp<SkROBuffer> buffer)
: ro_buffer_(std::move(buffer)),
position_of_block_(0),
iter_(ro_buffer_.get()) {}
size_t ROBufferSegmentReader::size() const {
return ro_buffer_ ? ro_buffer_->size() : 0;
}
size_t ROBufferSegmentReader::GetSomeData(const char*& data,
size_t position) const {
if (!ro_buffer_)
return 0;
MutexLocker lock(read_mutex_);
if (position < position_of_block_) {
// SkROBuffer::Iter only iterates forwards. Start from the beginning.
iter_.reset(ro_buffer_.get());
position_of_block_ = 0;
}
for (size_t size_of_block = iter_.size(); size_of_block != 0;
position_of_block_ += size_of_block, size_of_block = iter_.size()) {
DCHECK_LE(position_of_block_, position);
if (position_of_block_ + size_of_block > position) {
// |position| is in this block.
const size_t position_in_block = position - position_of_block_;
data = static_cast<const char*>(iter_.data()) + position_in_block;
return size_of_block - position_in_block;
}
// Move to next block.
if (!iter_.next()) {
// Reset to the beginning, so future calls can succeed.
iter_.reset(ro_buffer_.get());
position_of_block_ = 0;
return 0;
}
}
return 0;
}
static void UnrefROBuffer(const void* ptr, void* context) {
static_cast<SkROBuffer*>(context)->unref();
}
sk_sp<SkData> ROBufferSegmentReader::GetAsSkData() const {
if (!ro_buffer_)
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());
if (!multiple_blocks) {
// Contiguous data. No need to copy.
ro_buffer_->ref();
return SkData::MakeWithProc(iter.data(), iter.size(), &UnrefROBuffer,
ro_buffer_.get());
}
sk_sp<SkData> data = SkData::MakeUninitialized(ro_buffer_->size());
char* dst = static_cast<char*>(data->writable_data());
do {
size_t size = iter.size();
memcpy(dst, iter.data(), size);
dst += size;
} while (iter.next());
return data;
}
// SegmentReader ---------------------------------------------------------------
scoped_refptr<SegmentReader> SegmentReader::CreateFromSharedBuffer(
scoped_refptr<SharedBuffer> buffer) {
return base::AdoptRef(new SharedBufferSegmentReader(std::move(buffer)));
}
scoped_refptr<SegmentReader> SegmentReader::CreateFromSkData(
sk_sp<SkData> data) {
return base::AdoptRef(new DataSegmentReader(std::move(data)));
}
scoped_refptr<SegmentReader> SegmentReader::CreateFromSkROBuffer(
sk_sp<SkROBuffer> buffer) {
return base::AdoptRef(new ROBufferSegmentReader(std::move(buffer)));
}
} // namespace blink