| Index: third_party/WebKit/Source/platform/SharedBufferStep.cpp
|
| diff --git a/third_party/WebKit/Source/platform/SharedBufferStep.cpp b/third_party/WebKit/Source/platform/SharedBufferStep.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..75394495f07a1bbce78fe8d22075808351a598ca
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/platform/SharedBufferStep.cpp
|
| @@ -0,0 +1,301 @@
|
| +// Copyright 2017 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 "platform/SharedBufferStep.h"
|
| +#include "platform/SharedBuffer.h"
|
| +
|
| +namespace blink {
|
| +
|
| +static inline size_t SegmentIndex(size_t position) {
|
| + return position / SharedBuffer::kSegmentSize;
|
| +}
|
| +
|
| +static inline size_t OffsetInSegment(size_t position) {
|
| + return position % SharedBuffer::kSegmentSize;
|
| +}
|
| +
|
| +static inline char* AllocateSegment() {
|
| + return static_cast<char*>(WTF::Partitions::FastMalloc(
|
| + SharedBuffer::kSegmentSize, "blink::SharedBufferStep"));
|
| +}
|
| +
|
| +static inline void FreeSegment(char* p) {
|
| + WTF::Partitions::FastFree(p);
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep::BufferVector>
|
| +SharedBufferStep::BufferVector::AdoptVector(Vector<char>& vector) {
|
| + RefPtr<SharedBufferStep::BufferVector> buffer = BufferVector::Create();
|
| + buffer->vector_.swap(vector);
|
| + return buffer.Release();
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep::BufferVector>
|
| +SharedBufferStep::BufferVector::ForwardStep() {
|
| + RefPtr<SharedBufferStep::BufferVector> next_step = BufferVector::Create();
|
| + next_step->Append(data(), size());
|
| + return next_step.Release();
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep::SegmentVector>
|
| +SharedBufferStep::SegmentVector::ForwardStep() {
|
| + RefPtr<SegmentVector> next_step = SegmentVector::Create(segmented_position_);
|
| + next_step->vector_.Append(vector_.data(), vector_.size());
|
| + next_step->segmented_position_ = segmented_position_;
|
| + next_step->segmented_size_ = segmented_size_;
|
| + next_step_segments_ = next_step;
|
| + return next_step.Release();
|
| +}
|
| +
|
| +SharedBufferStep::SegmentVector::~SegmentVector() {
|
| + clear();
|
| +}
|
| +
|
| +void SharedBufferStep::SegmentVector::clear() {
|
| + if (next_step_segments_) {
|
| + return;
|
| + }
|
| +
|
| + for (size_t i = 0; i < vector_.size(); ++i) {
|
| + FreeSegment(vector_.at(i));
|
| + }
|
| +
|
| + vector_.clear();
|
| + segmented_position_ = 0;
|
| + segmented_size_ = 0;
|
| + next_step_segments_ = nullptr;
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep> SharedBufferStep::AdoptVector(
|
| + Vector<char>& vector) {
|
| + RefPtr<BufferVector> buffer = BufferVector::AdoptVector(vector);
|
| + RefPtr<SegmentVector> segments = SegmentVector::Create(vector.size());
|
| + RefPtr<SharedBufferStep> step =
|
| + SharedBufferStep::Create(vector.size(), buffer, segments);
|
| + return step.Release();
|
| +}
|
| +
|
| +size_t SharedBufferStep::GetSomeData(const char*& some_data,
|
| + size_t position) const {
|
| + size_t total_size = size();
|
| + if (position >= total_size) {
|
| + some_data = 0;
|
| + return 0;
|
| + }
|
| +
|
| + SECURITY_DCHECK(position < size_);
|
| + size_t available_size = 0;
|
| + size_t max_available_size = size_ - position;
|
| +
|
| + size_t consecutive_size = buffer_->size();
|
| + if (position < consecutive_size) {
|
| + some_data = buffer_->data() + position;
|
| + available_size = consecutive_size - position;
|
| + return std::min(available_size, max_available_size);
|
| + }
|
| +
|
| + position -= segments_->segmented_position();
|
| + size_t segments = segments_->size();
|
| + size_t segment = SegmentIndex(position);
|
| + if (segment < segments) {
|
| + size_t position_in_segment = OffsetInSegment(position);
|
| + some_data = segments_->at(segment) + position_in_segment;
|
| + if (segment == segments - 1) {
|
| + available_size = segments_->segmented_size() - position;
|
| + } else {
|
| + available_size = SharedBuffer::kSegmentSize - position_in_segment;
|
| + }
|
| + return std::min(available_size, max_available_size);
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return 0;
|
| +}
|
| +
|
| +bool SharedBufferStep::GetBytes(void* dest, size_t byte_length) const {
|
| + if (!dest)
|
| + return false;
|
| +
|
| + const char* segment = nullptr;
|
| + size_t load_position = 0;
|
| + size_t write_position = 0;
|
| + while (byte_length > 0) {
|
| + size_t load_size = GetSomeData(segment, load_position);
|
| + if (load_size == 0)
|
| + break;
|
| +
|
| + if (byte_length < load_size)
|
| + load_size = byte_length;
|
| + memcpy(static_cast<char*>(dest) + write_position, segment, load_size);
|
| + load_position += load_size;
|
| + write_position += load_size;
|
| + byte_length -= load_size;
|
| + }
|
| +
|
| + return byte_length == 0;
|
| +}
|
| +
|
| +sk_sp<SkData> SharedBufferStep::GetAsSkData() const {
|
| + size_t buffer_length = size();
|
| + sk_sp<SkData> data = SkData::MakeUninitialized(buffer_length);
|
| + char* buffer = static_cast<char*>(data->writable_data());
|
| +
|
| + if (GetBytes(buffer, buffer_length)) {
|
| + // Don't return the incomplete SkData.
|
| + return data;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return nullptr;
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep> SharedBufferStep::Copy() const {
|
| + RefPtr<SharedBufferStep> clone(AdoptRef(new SharedBufferStep));
|
| + clone->size_ = size_;
|
| + clone->buffer_->ReserveInitialCapacity(size_);
|
| + clone->buffer_->Append(buffer_->data(), buffer_->size());
|
| + if (!segments_->IsEmpty()) {
|
| + const char* segment = 0;
|
| + size_t position = buffer_->size();
|
| + while (size_t segment_size = GetSomeData(segment, position)) {
|
| + clone->buffer_->Append(segment, segment_size);
|
| + position += segment_size;
|
| + }
|
| + DCHECK_EQ(position, clone->size());
|
| + }
|
| + return clone.Release();
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep> SharedBufferStep::Append(
|
| + const char* data,
|
| + size_t length,
|
| + bool forward_step_if_needed) {
|
| + RefPtr<SharedBufferStep> next_step(this);
|
| + if (!length) {
|
| + return next_step.Release();
|
| + }
|
| +
|
| + DCHECK_GE(size_, buffer_->size());
|
| +
|
| + if (size_ + length <= SharedBuffer::kSegmentSize) {
|
| + // No need to use segments for small resource data.
|
| + if (forward_step_if_needed &&
|
| + buffer_->capacity() < buffer_->size() + length) {
|
| + RefPtr<BufferVector> next_step_buffer = buffer_->ForwardStep();
|
| + next_step =
|
| + AdoptRef(new SharedBufferStep(size_, next_step_buffer, segments_));
|
| + }
|
| +
|
| + next_step->buffer_->Append(data, length);
|
| + next_step->size_ += length;
|
| + next_step->segments_->set_segmented_position(next_step->size_);
|
| + return next_step.Release();
|
| + }
|
| +
|
| + size_t dst_segmented_size = segments_->segmented_size() + length;
|
| +
|
| + if (forward_step_if_needed) {
|
| + size_t dst_segments_count =
|
| + dst_segmented_size / SharedBuffer::kSegmentSize +
|
| + ((dst_segmented_size % SharedBuffer::kSegmentSize != 0) ? 1 : 0);
|
| + if (segments_->capacity() < dst_segments_count) {
|
| + RefPtr<SegmentVector> next_step_segments = segments_->ForwardStep();
|
| + next_step =
|
| + AdoptRef(new SharedBufferStep(size_, buffer_, next_step_segments));
|
| + }
|
| + }
|
| +
|
| + RefPtr<SegmentVector> dst_segments = next_step->segments_;
|
| +
|
| + size_t position_in_segment = OffsetInSegment(dst_segments->segmented_size());
|
| +
|
| + char* segment;
|
| + if (!position_in_segment) {
|
| + segment = AllocateSegment();
|
| + dst_segments->push_back(segment);
|
| + } else {
|
| + segment = dst_segments->back() + position_in_segment;
|
| + }
|
| +
|
| + size_t segment_free_space = SharedBuffer::kSegmentSize - position_in_segment;
|
| + size_t bytes_to_copy = std::min(length, segment_free_space);
|
| + size_t bytes_for_fill = length;
|
| +
|
| + for (;;) {
|
| + memcpy(segment, data, bytes_to_copy);
|
| + if (bytes_for_fill == bytes_to_copy)
|
| + break;
|
| +
|
| + bytes_for_fill -= bytes_to_copy;
|
| + data += bytes_to_copy;
|
| + segment = AllocateSegment();
|
| + dst_segments->push_back(segment);
|
| + bytes_to_copy = std::min(bytes_for_fill,
|
| + static_cast<size_t>(SharedBuffer::kSegmentSize));
|
| + }
|
| +
|
| + dst_segments->set_segmented_size(dst_segmented_size);
|
| + next_step->size_ += length;
|
| + return next_step.Release();
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep> SharedBufferStep::MergeSegmentsIntoBuffer(
|
| + bool forward_step_if_needed) const {
|
| + SharedBufferStep* step = const_cast<SharedBufferStep*>(this);
|
| + RefPtr<SharedBufferStep> next_step(step);
|
| + size_t buffer_size = buffer_->size();
|
| + if (size_ <= buffer_size) {
|
| + return next_step.Release();
|
| + }
|
| +
|
| + RefPtr<SegmentVector> next_step_segments = SegmentVector::Create(size_);
|
| +
|
| + if (forward_step_if_needed) {
|
| + RefPtr<BufferVector> next_step_buffer = buffer_;
|
| + if (buffer_->capacity() < size_) {
|
| + next_step_buffer = buffer_->ForwardStep();
|
| + }
|
| + next_step = AdoptRef(
|
| + new SharedBufferStep(size_, next_step_buffer, next_step_segments));
|
| + }
|
| +
|
| + RefPtr<BufferVector> dst_buffer = next_step->buffer_;
|
| +
|
| + size_t bytesLeft = size_ - buffer_size;
|
| + for (size_t i = 0; i < segments_->size(); ++i) {
|
| + size_t bytes_to_copy =
|
| + std::min(bytesLeft, static_cast<size_t>(SharedBuffer::kSegmentSize));
|
| + dst_buffer->Append(segments_->at(i), bytes_to_copy);
|
| + bytesLeft -= bytes_to_copy;
|
| + }
|
| +
|
| + if (!forward_step_if_needed) {
|
| + segments_ = next_step_segments;
|
| + }
|
| +
|
| + return next_step.Release();
|
| +}
|
| +
|
| +PassRefPtr<SharedBufferStep> SharedBufferStep::Clear(
|
| + bool forward_step_if_needed) {
|
| + if (forward_step_if_needed) {
|
| + return SharedBufferStep::Create();
|
| + }
|
| +
|
| + buffer_->clear();
|
| + segments_->clear();
|
| + size_ = 0;
|
| + return this;
|
| +}
|
| +
|
| +SharedBufferStep::SharedBufferStep() : size_(0) {
|
| + buffer_ = BufferVector::Create();
|
| + segments_ = SegmentVector::Create(0);
|
| +}
|
| +
|
| +SharedBufferStep::SharedBufferStep(size_t size) : size_(size) {
|
| + buffer_ = BufferVector::Create(size);
|
| + segments_ = SegmentVector::Create(size);
|
| +}
|
| +}
|
|
|