| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "platform/SharedBufferStep.h" |
| 6 #include "platform/SharedBuffer.h" |
| 7 |
| 8 namespace blink { |
| 9 |
| 10 static inline size_t SegmentIndex(size_t position) { |
| 11 return position / SharedBuffer::kSegmentSize; |
| 12 } |
| 13 |
| 14 static inline size_t OffsetInSegment(size_t position) { |
| 15 return position % SharedBuffer::kSegmentSize; |
| 16 } |
| 17 |
| 18 static inline char* AllocateSegment() { |
| 19 return static_cast<char*>(WTF::Partitions::FastMalloc( |
| 20 SharedBuffer::kSegmentSize, "blink::SharedBufferStep")); |
| 21 } |
| 22 |
| 23 static inline void FreeSegment(char* p) { |
| 24 WTF::Partitions::FastFree(p); |
| 25 } |
| 26 |
| 27 PassRefPtr<SharedBufferStep::BufferVector> |
| 28 SharedBufferStep::BufferVector::AdoptVector(Vector<char>& vector) { |
| 29 RefPtr<SharedBufferStep::BufferVector> buffer = BufferVector::Create(); |
| 30 buffer->vector_.swap(vector); |
| 31 return buffer.Release(); |
| 32 } |
| 33 |
| 34 PassRefPtr<SharedBufferStep::BufferVector> |
| 35 SharedBufferStep::BufferVector::ForwardStep() { |
| 36 RefPtr<SharedBufferStep::BufferVector> next_step = BufferVector::Create(); |
| 37 next_step->Append(data(), size()); |
| 38 return next_step.Release(); |
| 39 } |
| 40 |
| 41 PassRefPtr<SharedBufferStep::SegmentVector> |
| 42 SharedBufferStep::SegmentVector::ForwardStep() { |
| 43 RefPtr<SegmentVector> next_step = SegmentVector::Create(segmented_position_); |
| 44 next_step->vector_.Append(vector_.data(), vector_.size()); |
| 45 next_step->segmented_position_ = segmented_position_; |
| 46 next_step->segmented_size_ = segmented_size_; |
| 47 next_step_segments_ = next_step; |
| 48 return next_step.Release(); |
| 49 } |
| 50 |
| 51 SharedBufferStep::SegmentVector::~SegmentVector() { |
| 52 clear(); |
| 53 } |
| 54 |
| 55 void SharedBufferStep::SegmentVector::clear() { |
| 56 if (next_step_segments_) { |
| 57 return; |
| 58 } |
| 59 |
| 60 for (size_t i = 0; i < vector_.size(); ++i) { |
| 61 FreeSegment(vector_.at(i)); |
| 62 } |
| 63 |
| 64 vector_.clear(); |
| 65 segmented_position_ = 0; |
| 66 segmented_size_ = 0; |
| 67 next_step_segments_ = nullptr; |
| 68 } |
| 69 |
| 70 PassRefPtr<SharedBufferStep> SharedBufferStep::AdoptVector( |
| 71 Vector<char>& vector) { |
| 72 RefPtr<BufferVector> buffer = BufferVector::AdoptVector(vector); |
| 73 RefPtr<SegmentVector> segments = SegmentVector::Create(vector.size()); |
| 74 RefPtr<SharedBufferStep> step = |
| 75 SharedBufferStep::Create(vector.size(), buffer, segments); |
| 76 return step.Release(); |
| 77 } |
| 78 |
| 79 size_t SharedBufferStep::GetSomeData(const char*& some_data, |
| 80 size_t position) const { |
| 81 size_t total_size = size(); |
| 82 if (position >= total_size) { |
| 83 some_data = 0; |
| 84 return 0; |
| 85 } |
| 86 |
| 87 SECURITY_DCHECK(position < size_); |
| 88 size_t available_size = 0; |
| 89 size_t max_available_size = size_ - position; |
| 90 |
| 91 size_t consecutive_size = buffer_->size(); |
| 92 if (position < consecutive_size) { |
| 93 some_data = buffer_->data() + position; |
| 94 available_size = consecutive_size - position; |
| 95 return std::min(available_size, max_available_size); |
| 96 } |
| 97 |
| 98 position -= segments_->segmented_position(); |
| 99 size_t segments = segments_->size(); |
| 100 size_t segment = SegmentIndex(position); |
| 101 if (segment < segments) { |
| 102 size_t position_in_segment = OffsetInSegment(position); |
| 103 some_data = segments_->at(segment) + position_in_segment; |
| 104 if (segment == segments - 1) { |
| 105 available_size = segments_->segmented_size() - position; |
| 106 } else { |
| 107 available_size = SharedBuffer::kSegmentSize - position_in_segment; |
| 108 } |
| 109 return std::min(available_size, max_available_size); |
| 110 } |
| 111 |
| 112 NOTREACHED(); |
| 113 return 0; |
| 114 } |
| 115 |
| 116 bool SharedBufferStep::GetBytes(void* dest, size_t byte_length) const { |
| 117 if (!dest) |
| 118 return false; |
| 119 |
| 120 const char* segment = nullptr; |
| 121 size_t load_position = 0; |
| 122 size_t write_position = 0; |
| 123 while (byte_length > 0) { |
| 124 size_t load_size = GetSomeData(segment, load_position); |
| 125 if (load_size == 0) |
| 126 break; |
| 127 |
| 128 if (byte_length < load_size) |
| 129 load_size = byte_length; |
| 130 memcpy(static_cast<char*>(dest) + write_position, segment, load_size); |
| 131 load_position += load_size; |
| 132 write_position += load_size; |
| 133 byte_length -= load_size; |
| 134 } |
| 135 |
| 136 return byte_length == 0; |
| 137 } |
| 138 |
| 139 sk_sp<SkData> SharedBufferStep::GetAsSkData() const { |
| 140 size_t buffer_length = size(); |
| 141 sk_sp<SkData> data = SkData::MakeUninitialized(buffer_length); |
| 142 char* buffer = static_cast<char*>(data->writable_data()); |
| 143 |
| 144 if (GetBytes(buffer, buffer_length)) { |
| 145 // Don't return the incomplete SkData. |
| 146 return data; |
| 147 } |
| 148 |
| 149 NOTREACHED(); |
| 150 return nullptr; |
| 151 } |
| 152 |
| 153 PassRefPtr<SharedBufferStep> SharedBufferStep::Copy() const { |
| 154 RefPtr<SharedBufferStep> clone(AdoptRef(new SharedBufferStep)); |
| 155 clone->size_ = size_; |
| 156 clone->buffer_->ReserveInitialCapacity(size_); |
| 157 clone->buffer_->Append(buffer_->data(), buffer_->size()); |
| 158 if (!segments_->IsEmpty()) { |
| 159 const char* segment = 0; |
| 160 size_t position = buffer_->size(); |
| 161 while (size_t segment_size = GetSomeData(segment, position)) { |
| 162 clone->buffer_->Append(segment, segment_size); |
| 163 position += segment_size; |
| 164 } |
| 165 DCHECK_EQ(position, clone->size()); |
| 166 } |
| 167 return clone.Release(); |
| 168 } |
| 169 |
| 170 PassRefPtr<SharedBufferStep> SharedBufferStep::Append( |
| 171 const char* data, |
| 172 size_t length, |
| 173 bool forward_step_if_needed) { |
| 174 RefPtr<SharedBufferStep> next_step(this); |
| 175 if (!length) { |
| 176 return next_step.Release(); |
| 177 } |
| 178 |
| 179 DCHECK_GE(size_, buffer_->size()); |
| 180 |
| 181 if (size_ + length <= SharedBuffer::kSegmentSize) { |
| 182 // No need to use segments for small resource data. |
| 183 if (forward_step_if_needed && |
| 184 buffer_->capacity() < buffer_->size() + length) { |
| 185 RefPtr<BufferVector> next_step_buffer = buffer_->ForwardStep(); |
| 186 next_step = |
| 187 AdoptRef(new SharedBufferStep(size_, next_step_buffer, segments_)); |
| 188 } |
| 189 |
| 190 next_step->buffer_->Append(data, length); |
| 191 next_step->size_ += length; |
| 192 next_step->segments_->set_segmented_position(next_step->size_); |
| 193 return next_step.Release(); |
| 194 } |
| 195 |
| 196 size_t dst_segmented_size = segments_->segmented_size() + length; |
| 197 |
| 198 if (forward_step_if_needed) { |
| 199 size_t dst_segments_count = |
| 200 dst_segmented_size / SharedBuffer::kSegmentSize + |
| 201 ((dst_segmented_size % SharedBuffer::kSegmentSize != 0) ? 1 : 0); |
| 202 if (segments_->capacity() < dst_segments_count) { |
| 203 RefPtr<SegmentVector> next_step_segments = segments_->ForwardStep(); |
| 204 next_step = |
| 205 AdoptRef(new SharedBufferStep(size_, buffer_, next_step_segments)); |
| 206 } |
| 207 } |
| 208 |
| 209 RefPtr<SegmentVector> dst_segments = next_step->segments_; |
| 210 |
| 211 size_t position_in_segment = OffsetInSegment(dst_segments->segmented_size()); |
| 212 |
| 213 char* segment; |
| 214 if (!position_in_segment) { |
| 215 segment = AllocateSegment(); |
| 216 dst_segments->push_back(segment); |
| 217 } else { |
| 218 segment = dst_segments->back() + position_in_segment; |
| 219 } |
| 220 |
| 221 size_t segment_free_space = SharedBuffer::kSegmentSize - position_in_segment; |
| 222 size_t bytes_to_copy = std::min(length, segment_free_space); |
| 223 size_t bytes_for_fill = length; |
| 224 |
| 225 for (;;) { |
| 226 memcpy(segment, data, bytes_to_copy); |
| 227 if (bytes_for_fill == bytes_to_copy) |
| 228 break; |
| 229 |
| 230 bytes_for_fill -= bytes_to_copy; |
| 231 data += bytes_to_copy; |
| 232 segment = AllocateSegment(); |
| 233 dst_segments->push_back(segment); |
| 234 bytes_to_copy = std::min(bytes_for_fill, |
| 235 static_cast<size_t>(SharedBuffer::kSegmentSize)); |
| 236 } |
| 237 |
| 238 dst_segments->set_segmented_size(dst_segmented_size); |
| 239 next_step->size_ += length; |
| 240 return next_step.Release(); |
| 241 } |
| 242 |
| 243 PassRefPtr<SharedBufferStep> SharedBufferStep::MergeSegmentsIntoBuffer( |
| 244 bool forward_step_if_needed) const { |
| 245 SharedBufferStep* step = const_cast<SharedBufferStep*>(this); |
| 246 RefPtr<SharedBufferStep> next_step(step); |
| 247 size_t buffer_size = buffer_->size(); |
| 248 if (size_ <= buffer_size) { |
| 249 return next_step.Release(); |
| 250 } |
| 251 |
| 252 RefPtr<SegmentVector> next_step_segments = SegmentVector::Create(size_); |
| 253 |
| 254 if (forward_step_if_needed) { |
| 255 RefPtr<BufferVector> next_step_buffer = buffer_; |
| 256 if (buffer_->capacity() < size_) { |
| 257 next_step_buffer = buffer_->ForwardStep(); |
| 258 } |
| 259 next_step = AdoptRef( |
| 260 new SharedBufferStep(size_, next_step_buffer, next_step_segments)); |
| 261 } |
| 262 |
| 263 RefPtr<BufferVector> dst_buffer = next_step->buffer_; |
| 264 |
| 265 size_t bytesLeft = size_ - buffer_size; |
| 266 for (size_t i = 0; i < segments_->size(); ++i) { |
| 267 size_t bytes_to_copy = |
| 268 std::min(bytesLeft, static_cast<size_t>(SharedBuffer::kSegmentSize)); |
| 269 dst_buffer->Append(segments_->at(i), bytes_to_copy); |
| 270 bytesLeft -= bytes_to_copy; |
| 271 } |
| 272 |
| 273 if (!forward_step_if_needed) { |
| 274 segments_ = next_step_segments; |
| 275 } |
| 276 |
| 277 return next_step.Release(); |
| 278 } |
| 279 |
| 280 PassRefPtr<SharedBufferStep> SharedBufferStep::Clear( |
| 281 bool forward_step_if_needed) { |
| 282 if (forward_step_if_needed) { |
| 283 return SharedBufferStep::Create(); |
| 284 } |
| 285 |
| 286 buffer_->clear(); |
| 287 segments_->clear(); |
| 288 size_ = 0; |
| 289 return this; |
| 290 } |
| 291 |
| 292 SharedBufferStep::SharedBufferStep() : size_(0) { |
| 293 buffer_ = BufferVector::Create(); |
| 294 segments_ = SegmentVector::Create(0); |
| 295 } |
| 296 |
| 297 SharedBufferStep::SharedBufferStep(size_t size) : size_(size) { |
| 298 buffer_ = BufferVector::Create(size); |
| 299 segments_ = SegmentVector::Create(size); |
| 300 } |
| 301 } |
| OLD | NEW |