Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: src/core/SkPictureFlat.h

Issue 1930103003: remove SkWriteBuffer::reserve() (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: More dead code. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/core/SkPaint.cpp ('k') | src/core/SkPictureFlat.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #ifndef SkPictureFlat_DEFINED 7 #ifndef SkPictureFlat_DEFINED
8 #define SkPictureFlat_DEFINED 8 #define SkPictureFlat_DEFINED
9 9
10 10
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 156
157 void setupBuffer(SkReadBuffer& buffer) const { 157 void setupBuffer(SkReadBuffer& buffer) const {
158 buffer.setFactoryPlayback(fArray, fCount); 158 buffer.setFactoryPlayback(fArray, fCount);
159 } 159 }
160 160
161 private: 161 private:
162 int fCount; 162 int fCount;
163 SkFlattenable::Factory* fArray; 163 SkFlattenable::Factory* fArray;
164 }; 164 };
165 165
166 ///////////////////////////////////////////////////////////////////////////////
167 //
168 //
169 // The following templated classes provide an efficient way to store and compare
170 // objects that have been flattened (i.e. serialized in an ordered binary
171 // format).
172 //
173 // SkFlatData: is a simple indexable container for the flattened data
174 // which is agnostic to the type of data is is indexing. It is
175 // also responsible for flattening/unflattening objects but
176 // details of that operation are hidden in the provided traits
177 // SkFlatDictionary: is an abstract templated dictionary that maintains a
178 // searchable set of SkFlatData objects of type T.
179 // SkFlatController: is an interface provided to SkFlatDictionary which handles
180 // allocation (and unallocation in some cases). It also holds
181 // ref count recorders and the like.
182 //
183 // NOTE: any class that wishes to be used in conjunction with SkFlatDictionary m ust subclass the
184 // dictionary and provide the necessary flattening traits. SkFlatController mus t also be
185 // implemented, or SkChunkFlatController can be used to use an SkChunkAllocator and never do
186 // replacements.
187 //
188 //
189 ///////////////////////////////////////////////////////////////////////////////
190
191 class SkFlatData;
192
193 class SkFlatController : public SkRefCnt {
194 public:
195
196
197 SkFlatController(uint32_t writeBufferFlags = 0);
198 virtual ~SkFlatController();
199 /**
200 * Return a new block of memory for the SkFlatDictionary to use.
201 * This memory is owned by the controller and has the same lifetime unless y ou
202 * call unalloc(), in which case it may be freed early.
203 */
204 virtual void* allocThrow(size_t bytes) = 0;
205
206 /**
207 * Hint that this block, which was allocated with allocThrow, is no longer n eeded.
208 * The implementation may choose to free this memory any time beteween now a nd destruction.
209 */
210 virtual void unalloc(void* ptr) = 0;
211
212 /**
213 * Used during creation and unflattening of SkFlatData objects. If the
214 * objects being flattened contain bitmaps they are stored in this heap
215 * and the flattenable stores the index to the bitmap on the heap.
216 * This should be set by the protected setBitmapHeap.
217 */
218 SkBitmapHeap* getBitmapHeap() { return fBitmapHeap; }
219
220 /**
221 * Used during creation of SkFlatData objects. If a typeface recorder is
222 * required to flatten the objects being flattened (i.e. for SkPaints), this
223 * should be set by the protected setTypefaceSet.
224 */
225 SkRefCntSet* getTypefaceSet() { return fTypefaceSet; }
226
227 /**
228 * Used during unflattening of the SkFlatData objects in the
229 * SkFlatDictionary. Needs to be set by the protected setTypefacePlayback
230 * and needs to be reset to the SkRefCntSet passed to setTypefaceSet.
231 */
232 SkTypefacePlayback* getTypefacePlayback() { return fTypefacePlayback; }
233
234 /**
235 * Flags to use during creation of SkFlatData objects. Defaults to zero.
236 */
237 uint32_t getWriteBufferFlags() { return fWriteBufferFlags; }
238
239 protected:
240 /**
241 * Set an SkBitmapHeap to be used to store/read SkBitmaps. Ref counted.
242 */
243 void setBitmapHeap(SkBitmapHeap*);
244
245 /**
246 * Set an SkRefCntSet to be used to store SkTypefaces during flattening. Ref
247 * counted.
248 */
249 void setTypefaceSet(SkRefCntSet*);
250
251 /**
252 * Set an SkTypefacePlayback to be used to find references to SkTypefaces
253 * during unflattening. Should be reset to the set provided to
254 * setTypefaceSet.
255 */
256 void setTypefacePlayback(SkTypefacePlayback*);
257
258 private:
259 SkBitmapHeap* fBitmapHeap;
260 SkRefCntSet* fTypefaceSet;
261 SkTypefacePlayback* fTypefacePlayback;
262 const uint32_t fWriteBufferFlags;
263
264 typedef SkRefCnt INHERITED;
265 };
266
267 class SkFlatData {
268 public:
269 // Flatten obj into an SkFlatData with this index. controller owns the SkFl atData*.
270 template <typename Traits, typename T>
271 static SkFlatData* Create(SkFlatController* controller, const T& obj, int in dex) {
272 // A buffer of 256 bytes should fit most paints, regions, and matrices.
273 uint32_t storage[64];
274 SkWriteBuffer buffer(storage, sizeof(storage), controller->getWriteBuffe rFlags());
275
276 buffer.setBitmapHeap(controller->getBitmapHeap());
277 buffer.setTypefaceRecorder(controller->getTypefaceSet());
278
279 Traits::Flatten(buffer, obj);
280 size_t size = buffer.bytesWritten();
281 SkASSERT(SkIsAlign4(size));
282
283 // Allocate enough memory to hold SkFlatData struct and the flat data it self.
284 size_t allocSize = sizeof(SkFlatData) + size;
285 SkFlatData* result = (SkFlatData*) controller->allocThrow(allocSize);
286
287 // Put the serialized contents into the data section of the new allocati on.
288 buffer.writeToMemory(result->data());
289 // Stamp the index, size and checksum in the header.
290 result->stampHeader(index, SkToS32(size));
291 return result;
292 }
293
294 // Unflatten this into result, using bitmapHeap and facePlayback for bitmaps and fonts if given
295 template <typename Traits, typename T>
296 void unflatten(T* result,
297 SkBitmapHeap* bitmapHeap = nullptr,
298 SkTypefacePlayback* facePlayback = nullptr) const {
299 SkReadBuffer buffer(this->data(), fFlatSize);
300
301 if (bitmapHeap) {
302 buffer.setBitmapStorage(bitmapHeap);
303 }
304 if (facePlayback) {
305 facePlayback->setupBuffer(buffer);
306 }
307
308 Traits::Unflatten(buffer, result);
309 SkASSERT(fFlatSize == (int32_t)buffer.offset());
310 }
311
312 // Do these contain the same data? Ignores index() and topBot().
313 bool operator==(const SkFlatData& that) const {
314 if (this->checksum() != that.checksum() || this->flatSize() != that.flat Size()) {
315 return false;
316 }
317 return memcmp(this->data(), that.data(), this->flatSize()) == 0;
318 }
319
320 int index() const { return fIndex; }
321 const uint8_t* data() const { return (const uint8_t*)this + sizeof(*this); }
322 size_t flatSize() const { return fFlatSize; }
323 uint32_t checksum() const { return fChecksum; }
324
325 // Returns true if fTopBot[] has been recorded.
326 bool isTopBotWritten() const {
327 return !SkScalarIsNaN(fTopBot[0]);
328 }
329
330 // Returns fTopBot array, so it can be passed to a routine to compute them.
331 // For efficiency, we assert that fTopBot have not been recorded yet.
332 SkScalar* writableTopBot() const {
333 SkASSERT(!this->isTopBotWritten());
334 return fTopBot;
335 }
336
337 // Return the topbot[] after it has been recorded.
338 const SkScalar* topBot() const {
339 SkASSERT(this->isTopBotWritten());
340 return fTopBot;
341 }
342
343 private:
344 struct HashTraits {
345 static const SkFlatData& GetKey(const SkFlatData& flat) { return flat; }
346 static uint32_t Hash(const SkFlatData& flat) { return flat.checksum(); }
347 };
348
349 void setIndex(int index) { fIndex = index; }
350 uint8_t* data() { return (uint8_t*)this + sizeof(*this); }
351
352 // This assumes the payload flat data has already been written and does not modify it.
353 void stampHeader(int index, int32_t size) {
354 SkASSERT(SkIsAlign4(size));
355 fIndex = index;
356 fFlatSize = size;
357 fTopBot[0] = SK_ScalarNaN; // Mark as unwritten.
358 fChecksum = SkChecksum::Murmur3(this->data(), size);
359 }
360
361 int fIndex;
362 int32_t fFlatSize;
363 uint32_t fChecksum;
364 mutable SkScalar fTopBot[2]; // Cache of FontMetrics fTop, fBottom. Starts as [NaN,?].
365 // uint32_t flattenedData[] implicitly hangs off the end.
366
367 template <typename T, typename Traits> friend class SkFlatDictionary;
368 };
369
370 template <typename T, typename Traits>
371 class SkFlatDictionary {
372 public:
373 explicit SkFlatDictionary(SkFlatController* controller)
374 : fController(SkRef(controller))
375 , fScratch(controller->getWriteBufferFlags())
376 , fReady(false) {
377 this->reset();
378 }
379
380 /**
381 * Clears the dictionary of all entries. However, it does NOT free the
382 * memory that was allocated for each entry (that's owned by controller).
383 */
384 void reset() {
385 fIndexedData.rewind();
386 }
387
388 int count() const {
389 SkASSERT(fHash.count() == fIndexedData.count());
390 return fHash.count();
391 }
392
393 // For testing only. Index is zero-based.
394 const SkFlatData* operator[](int index) {
395 return fIndexedData[index];
396 }
397
398 /**
399 * Given an element of type T return its 1-based index in the dictionary. If
400 * the element wasn't previously in the dictionary it is automatically
401 * added.
402 *
403 */
404 int find(const T& element) {
405 return this->findAndReturnFlat(element)->index();
406 }
407
408 /**
409 * Similar to find. Allows the caller to specify an SkFlatData to replace in
410 * the case of an add. Also tells the caller whether a new SkFlatData was
411 * added and whether the old one was replaced. The parameters added and
412 * replaced are required to be non-nullptr. Rather than returning the index of
413 * the entry in the dictionary, it returns the actual SkFlatData.
414 */
415 const SkFlatData* findAndReplace(const T& element,
416 const SkFlatData* toReplace,
417 bool* added,
418 bool* replaced) {
419 SkASSERT(added != nullptr && replaced != nullptr);
420
421 const int oldCount = this->count();
422 SkFlatData* flat = this->findAndReturnMutableFlat(element);
423 *added = this->count() > oldCount;
424
425 // If we don't want to replace anything, we're done.
426 if (!*added || toReplace == nullptr) {
427 *replaced = false;
428 return flat;
429 }
430
431 // If we don't have the thing to replace, we're done.
432 const SkFlatData* found = fHash.find(*toReplace);
433 if (found == nullptr) {
434 *replaced = false;
435 return flat;
436 }
437
438 // findAndReturnMutableFlat put flat at the back. Swap it into found->i ndex() instead.
439 // indices in SkFlatData are 1-based, while fIndexedData is 0-based. Wa tch out!
440 SkASSERT(flat->index() == this->count());
441 flat->setIndex(found->index());
442 fIndexedData.removeShuffle(found->index()-1);
443 SkASSERT(flat == fIndexedData[found->index()-1]);
444
445 // findAndReturnMutableFlat already called fHash.add(), so we just clean up the old entry.
446 fHash.remove(*found);
447 fController->unalloc((void*)found);
448 SkASSERT(this->count() == oldCount);
449
450 *replaced = true;
451 return flat;
452 }
453
454 /**
455 * Unflatten the specific object at the given index.
456 * Caller takes ownership of the result.
457 */
458 T* unflatten(int index) const {
459 // index is 1-based, while fIndexedData is 0-based.
460 const SkFlatData* element = fIndexedData[index-1];
461 SkASSERT(index == element->index());
462
463 T* dst = new T;
464 this->unflatten(dst, element);
465 return dst;
466 }
467
468 /**
469 * Find or insert a flattened version of element into the dictionary.
470 * Caller does not take ownership of the result. This will not return nullp tr.
471 */
472 const SkFlatData* findAndReturnFlat(const T& element) {
473 return this->findAndReturnMutableFlat(element);
474 }
475
476 private:
477 // We have to delay fScratch's initialization until its first use; fControll er might not
478 // be fully set up by the time we get it in the constructor.
479 void lazyInit() {
480 if (fReady) {
481 return;
482 }
483
484 // Without a bitmap heap, we'll flatten bitmaps into paints. That's nev er what you want.
485 SkASSERT(fController->getBitmapHeap() != nullptr);
486 fScratch.setBitmapHeap(fController->getBitmapHeap());
487 fScratch.setTypefaceRecorder(fController->getTypefaceSet());
488 fReady = true;
489 }
490
491 // As findAndReturnFlat, but returns a mutable pointer for internal use.
492 SkFlatData* findAndReturnMutableFlat(const T& element) {
493 // Only valid until the next call to resetScratch().
494 const SkFlatData& scratch = this->resetScratch(element, this->count()+1) ;
495
496 SkFlatData* candidate = fHash.find(scratch);
497 if (candidate != nullptr) {
498 return candidate;
499 }
500
501 SkFlatData* detached = this->detachScratch();
502 fHash.add(detached);
503 *fIndexedData.append() = detached;
504 SkASSERT(fIndexedData.top()->index() == this->count());
505 return detached;
506 }
507
508 // This reference is valid only until the next call to resetScratch() or det achScratch().
509 const SkFlatData& resetScratch(const T& element, int index) {
510 this->lazyInit();
511
512 // Layout of fScratch: [ SkFlatData header, 20 bytes ] [ data ..., 4-byt e aligned ]
513 fScratch.reset();
514 fScratch.reserve(sizeof(SkFlatData));
515 Traits::Flatten(fScratch, element);
516 const size_t dataSize = fScratch.bytesWritten() - sizeof(SkFlatData);
517
518 // Reinterpret data in fScratch as an SkFlatData.
519 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArr ay();
520 SkASSERT(scratch != nullptr);
521 scratch->stampHeader(index, SkToS32(dataSize));
522 return *scratch;
523 }
524
525 // This result is owned by fController and lives as long as it does (unless unalloc'd).
526 SkFlatData* detachScratch() {
527 // Allocate a new SkFlatData exactly big enough to hold our current scra tch.
528 // We use the controller for this allocation to extend the allocation's lifetime and allow
529 // the controller to do whatever memory management it wants.
530 SkFlatData* detached = (SkFlatData*)fController->allocThrow(fScratch.byt esWritten());
531
532 // Copy scratch into the new SkFlatData.
533 SkFlatData* scratch = (SkFlatData*)fScratch.getWriter32()->contiguousArr ay();
534 SkASSERT(scratch != nullptr);
535 memcpy(detached, scratch, fScratch.bytesWritten());
536
537 // We can now reuse fScratch, and detached will live until fController d ies.
538 return detached;
539 }
540
541 void unflatten(T* dst, const SkFlatData* element) const {
542 element->unflatten<Traits>(dst,
543 fController->getBitmapHeap(),
544 fController->getTypefacePlayback());
545 }
546
547 // All SkFlatData* stored in fIndexedData and fHash are owned by the control ler.
548 SkAutoTUnref<SkFlatController> fController;
549 SkWriteBuffer fScratch;
550 bool fReady;
551
552 // For index -> SkFlatData. 0-based, while all indices in the API are 1-bas ed. Careful!
553 SkTDArray<const SkFlatData*> fIndexedData;
554
555 // For SkFlatData -> cached SkFlatData, which has index().
556 SkTDynamicHash<SkFlatData, SkFlatData, SkFlatData::HashTraits> fHash;
557 };
558
559 #endif 166 #endif
OLDNEW
« no previous file with comments | « src/core/SkPaint.cpp ('k') | src/core/SkPictureFlat.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698