| Index: cc/paint/paint_op_buffer.cc
|
| diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
|
| deleted file mode 100644
|
| index fa62a418e9fce2bb5fee71e9f6eb057567ac9171..0000000000000000000000000000000000000000
|
| --- a/cc/paint/paint_op_buffer.cc
|
| +++ /dev/null
|
| @@ -1,566 +0,0 @@
|
| -// 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 "cc/paint/paint_op_buffer.h"
|
| -
|
| -#include "cc/paint/display_item_list.h"
|
| -#include "cc/paint/paint_record.h"
|
| -#include "third_party/skia/include/core/SkAnnotation.h"
|
| -
|
| -namespace cc {
|
| -
|
| -#define TYPES(M) \
|
| - M(AnnotateOp) \
|
| - M(ClipPathOp) \
|
| - M(ClipRectOp) \
|
| - M(ClipRRectOp) \
|
| - M(ConcatOp) \
|
| - M(DrawArcOp) \
|
| - M(DrawCircleOp) \
|
| - M(DrawColorOp) \
|
| - M(DrawDisplayItemListOp) \
|
| - M(DrawDRRectOp) \
|
| - M(DrawImageOp) \
|
| - M(DrawImageRectOp) \
|
| - M(DrawIRectOp) \
|
| - M(DrawLineOp) \
|
| - M(DrawOvalOp) \
|
| - M(DrawPathOp) \
|
| - M(DrawPosTextOp) \
|
| - M(DrawRecordOp) \
|
| - M(DrawRectOp) \
|
| - M(DrawRRectOp) \
|
| - M(DrawTextOp) \
|
| - M(DrawTextBlobOp) \
|
| - M(NoopOp) \
|
| - M(RestoreOp) \
|
| - M(RotateOp) \
|
| - M(SaveOp) \
|
| - M(SaveLayerOp) \
|
| - M(SaveLayerAlphaOp) \
|
| - M(ScaleOp) \
|
| - M(SetMatrixOp) \
|
| - M(TranslateOp)
|
| -
|
| -// Helper template to share common code for RasterWithAlpha when paint ops
|
| -// have or don't have PaintFlags.
|
| -template <typename T, bool HasFlags>
|
| -struct Rasterizer {
|
| - static void Raster(const T* op,
|
| - SkCanvas* canvas,
|
| - const SkMatrix& original_ctm) {
|
| - // Paint ops with kHasPaintFlags need to declare RasterWithPaintFlags
|
| - // otherwise, the paint op needs its own Raster function. Without its
|
| - // own, this becomes an infinite loop as PaintOp::Raster calls itself.
|
| - static_assert(
|
| - !std::is_same<decltype(&PaintOp::Raster), decltype(&T::Raster)>::value,
|
| - "No Raster function");
|
| -
|
| - op->Raster(canvas);
|
| - }
|
| - static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
|
| - DCHECK(T::kIsDrawOp);
|
| - // TODO(enne): is it ok to just drop the bounds here?
|
| - canvas->saveLayerAlpha(nullptr, alpha);
|
| - op->Raster(canvas);
|
| - canvas->restore();
|
| - }
|
| -};
|
| -
|
| -template <typename T>
|
| -struct Rasterizer<T, true> {
|
| - static void Raster(const T* op,
|
| - SkCanvas* canvas,
|
| - const SkMatrix& original_ctm) {
|
| - op->RasterWithFlags(canvas, op->flags);
|
| - }
|
| - static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
|
| - DCHECK(T::kIsDrawOp);
|
| - SkMatrix unused_matrix;
|
| - if (alpha == 255) {
|
| - Raster(op, canvas, unused_matrix);
|
| - } else if (op->flags.SupportsFoldingAlpha()) {
|
| - PaintFlags flags = op->flags;
|
| - flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha));
|
| - op->RasterWithFlags(canvas, flags);
|
| - } else {
|
| - canvas->saveLayerAlpha(nullptr, alpha);
|
| - op->RasterWithFlags(canvas, op->flags);
|
| - canvas->restore();
|
| - }
|
| - }
|
| -};
|
| -
|
| -template <>
|
| -struct Rasterizer<SetMatrixOp, false> {
|
| - static void Raster(const SetMatrixOp* op,
|
| - SkCanvas* canvas,
|
| - const SkMatrix& original_ctm) {
|
| - op->Raster(canvas, original_ctm);
|
| - }
|
| - static void RasterWithAlpha(const SetMatrixOp* op,
|
| - SkCanvas* canvas,
|
| - uint8_t alpha) {
|
| - NOTREACHED();
|
| - }
|
| -};
|
| -
|
| -template <>
|
| -struct Rasterizer<DrawRecordOp, false> {
|
| - static void Raster(const DrawRecordOp* op,
|
| - SkCanvas* canvas,
|
| - const SkMatrix& original_ctm) {
|
| - op->Raster(canvas);
|
| - }
|
| - static void RasterWithAlpha(const DrawRecordOp* op,
|
| - SkCanvas* canvas,
|
| - uint8_t alpha) {
|
| - // This "looking into records" optimization is done here instead of
|
| - // in the PaintOpBuffer::Raster function as DisplayItemList calls
|
| - // into RasterWithAlpha directly.
|
| - if (op->record->approximateOpCount() == 1) {
|
| - PaintOp* single_op = op->record->GetFirstOp();
|
| - // RasterWithAlpha only supported for draw ops.
|
| - if (single_op->IsDrawOp()) {
|
| - single_op->RasterWithAlpha(canvas, alpha);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - canvas->saveLayerAlpha(nullptr, alpha);
|
| - op->Raster(canvas);
|
| - canvas->restore();
|
| - }
|
| -};
|
| -
|
| -// TODO(enne): partially specialize RasterWithAlpha for draw color?
|
| -
|
| -static constexpr size_t kNumOpTypes =
|
| - static_cast<size_t>(PaintOpType::LastPaintOpType) + 1;
|
| -
|
| -// Verify that every op is in the TYPES macro.
|
| -#define M(T) +1
|
| -static_assert(kNumOpTypes == TYPES(M), "Missing op in list");
|
| -#undef M
|
| -
|
| -using RasterFunction = void (*)(const PaintOp* op,
|
| - SkCanvas* canvas,
|
| - const SkMatrix& original_ctm);
|
| -#define M(T) \
|
| - [](const PaintOp* op, SkCanvas* canvas, const SkMatrix& original_ctm) { \
|
| - Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \
|
| - canvas, original_ctm); \
|
| - },
|
| -static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
|
| -#undef M
|
| -
|
| -using RasterAlphaFunction = void (*)(const PaintOp* op,
|
| - SkCanvas* canvas,
|
| - uint8_t alpha);
|
| -#define M(T) \
|
| - T::kIsDrawOp ? \
|
| - [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \
|
| - Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \
|
| - static_cast<const T*>(op), canvas, alpha); \
|
| - } : static_cast<RasterAlphaFunction>(nullptr),
|
| -static const RasterAlphaFunction g_raster_alpha_functions[kNumOpTypes] = {
|
| - TYPES(M)};
|
| -#undef M
|
| -
|
| -// Most state ops (matrix, clip, save, restore) have a trivial destructor.
|
| -// TODO(enne): evaluate if we need the nullptr optimization or if
|
| -// we even need to differentiate trivial destructors here.
|
| -using VoidFunction = void (*)(PaintOp* op);
|
| -#define M(T) \
|
| - !std::is_trivially_destructible<T>::value \
|
| - ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
|
| - : static_cast<VoidFunction>(nullptr),
|
| -static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
|
| -#undef M
|
| -
|
| -#define M(T) T::kIsDrawOp,
|
| -static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)};
|
| -#undef M
|
| -
|
| -#define M(T) \
|
| - static_assert(sizeof(T) <= sizeof(LargestPaintOp), \
|
| - #T " must be no bigger than LargestPaintOp");
|
| -TYPES(M);
|
| -#undef M
|
| -
|
| -#undef TYPES
|
| -
|
| -SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
|
| -
|
| -void AnnotateOp::Raster(SkCanvas* canvas) const {
|
| - switch (annotation_type) {
|
| - case PaintCanvas::AnnotationType::URL:
|
| - SkAnnotateRectWithURL(canvas, rect, data.get());
|
| - break;
|
| - case PaintCanvas::AnnotationType::LINK_TO_DESTINATION:
|
| - SkAnnotateLinkToDestination(canvas, rect, data.get());
|
| - break;
|
| - case PaintCanvas::AnnotationType::NAMED_DESTINATION: {
|
| - SkPoint point = SkPoint::Make(rect.x(), rect.y());
|
| - SkAnnotateNamedDestination(canvas, point, data.get());
|
| - break;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void ClipPathOp::Raster(SkCanvas* canvas) const {
|
| - canvas->clipPath(path, op, antialias);
|
| -}
|
| -
|
| -void ClipRectOp::Raster(SkCanvas* canvas) const {
|
| - canvas->clipRect(rect, op, antialias);
|
| -}
|
| -
|
| -void ClipRRectOp::Raster(SkCanvas* canvas) const {
|
| - canvas->clipRRect(rrect, op, antialias);
|
| -}
|
| -
|
| -void ConcatOp::Raster(SkCanvas* canvas) const {
|
| - canvas->concat(matrix);
|
| -}
|
| -
|
| -void DrawArcOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawArc(oval, start_angle, sweep_angle, use_center, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawCircleOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawCircle(cx, cy, radius, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawColorOp::Raster(SkCanvas* canvas) const {
|
| - canvas->drawColor(color, mode);
|
| -}
|
| -
|
| -void DrawDisplayItemListOp::Raster(SkCanvas* canvas) const {
|
| - list->Raster(canvas, nullptr);
|
| -}
|
| -
|
| -void DrawDRRectOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawDRRect(outer, inner, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawImageOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawImage(image.sk_image().get(), left, top, ToSkPaint(&flags));
|
| -}
|
| -
|
| -void DrawImageRectOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - // TODO(enne): Probably PaintCanvas should just use the skia enum directly.
|
| - SkCanvas::SrcRectConstraint skconstraint =
|
| - static_cast<SkCanvas::SrcRectConstraint>(constraint);
|
| - canvas->drawImageRect(image.sk_image().get(), src, dst, ToSkPaint(&flags),
|
| - skconstraint);
|
| -}
|
| -
|
| -void DrawIRectOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawIRect(rect, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawLineOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawLine(x0, y0, x1, y1, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawOvalOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawOval(oval, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawPathOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawPath(path, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawPosTextOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawPosText(paint_op_data(this), bytes, paint_op_array<SkPoint>(this),
|
| - ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawRecordOp::Raster(SkCanvas* canvas) const {
|
| - record->playback(canvas);
|
| -}
|
| -
|
| -void DrawRectOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawRect(rect, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawRRectOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawRRect(rrect, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawTextOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawText(paint_op_data(this), bytes, x, y, ToSkPaint(flags));
|
| -}
|
| -
|
| -void DrawTextBlobOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - canvas->drawTextBlob(blob.get(), x, y, ToSkPaint(flags));
|
| -}
|
| -
|
| -void RestoreOp::Raster(SkCanvas* canvas) const {
|
| - canvas->restore();
|
| -}
|
| -
|
| -void RotateOp::Raster(SkCanvas* canvas) const {
|
| - canvas->rotate(degrees);
|
| -}
|
| -
|
| -void SaveOp::Raster(SkCanvas* canvas) const {
|
| - canvas->save();
|
| -}
|
| -
|
| -void SaveLayerOp::RasterWithFlags(SkCanvas* canvas,
|
| - const PaintFlags& flags) const {
|
| - // See PaintOp::kUnsetRect
|
| - bool unset = bounds.left() == SK_ScalarInfinity;
|
| -
|
| - canvas->saveLayer(unset ? nullptr : &bounds, ToSkPaint(&flags));
|
| -}
|
| -
|
| -void SaveLayerAlphaOp::Raster(SkCanvas* canvas) const {
|
| - // See PaintOp::kUnsetRect
|
| - bool unset = bounds.left() == SK_ScalarInfinity;
|
| - canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha);
|
| -}
|
| -
|
| -void ScaleOp::Raster(SkCanvas* canvas) const {
|
| - canvas->scale(sx, sy);
|
| -}
|
| -
|
| -void SetMatrixOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const {
|
| - canvas->setMatrix(SkMatrix::Concat(original_ctm, matrix));
|
| -}
|
| -
|
| -void TranslateOp::Raster(SkCanvas* canvas) const {
|
| - canvas->translate(dx, dy);
|
| -}
|
| -
|
| -bool PaintOp::IsDrawOp() const {
|
| - return g_is_draw_op[type];
|
| -}
|
| -
|
| -void PaintOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const {
|
| - g_raster_functions[type](this, canvas, original_ctm);
|
| -}
|
| -
|
| -void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const {
|
| - g_raster_alpha_functions[type](this, canvas, alpha);
|
| -}
|
| -
|
| -int ClipPathOp::CountSlowPaths() const {
|
| - return antialias && !path.isConvex() ? 1 : 0;
|
| -}
|
| -
|
| -int DrawLineOp::CountSlowPaths() const {
|
| - if (const SkPathEffect* effect = flags.getPathEffect()) {
|
| - SkPathEffect::DashInfo info;
|
| - SkPathEffect::DashType dashType = effect->asADash(&info);
|
| - if (flags.getStrokeCap() != PaintFlags::kRound_Cap &&
|
| - dashType == SkPathEffect::kDash_DashType && info.fCount == 2) {
|
| - // The PaintFlags will count this as 1, so uncount that here as
|
| - // this kind of line is special cased and not slow.
|
| - return -1;
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -int DrawPathOp::CountSlowPaths() const {
|
| - // This logic is copied from SkPathCounter instead of attempting to expose
|
| - // that from Skia.
|
| - if (!flags.isAntiAlias() || path.isConvex())
|
| - return 0;
|
| -
|
| - PaintFlags::Style paintStyle = flags.getStyle();
|
| - const SkRect& pathBounds = path.getBounds();
|
| - if (paintStyle == PaintFlags::kStroke_Style && flags.getStrokeWidth() == 0) {
|
| - // AA hairline concave path is not slow.
|
| - return 0;
|
| - } else if (paintStyle == PaintFlags::kFill_Style &&
|
| - pathBounds.width() < 64.f && pathBounds.height() < 64.f &&
|
| - !path.isVolatile()) {
|
| - // AADF eligible concave path is not slow.
|
| - return 0;
|
| - } else {
|
| - return 1;
|
| - }
|
| -}
|
| -
|
| -AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
|
| - const SkRect& rect,
|
| - sk_sp<SkData> data)
|
| - : annotation_type(annotation_type), rect(rect), data(std::move(data)) {}
|
| -
|
| -AnnotateOp::~AnnotateOp() = default;
|
| -
|
| -DrawDisplayItemListOp::DrawDisplayItemListOp(
|
| - scoped_refptr<DisplayItemList> list)
|
| - : list(list) {}
|
| -
|
| -size_t DrawDisplayItemListOp::AdditionalBytesUsed() const {
|
| - return list->ApproximateMemoryUsage();
|
| -}
|
| -
|
| -DrawDisplayItemListOp::DrawDisplayItemListOp(const DrawDisplayItemListOp& op) =
|
| - default;
|
| -
|
| -DrawDisplayItemListOp& DrawDisplayItemListOp::operator=(
|
| - const DrawDisplayItemListOp& op) = default;
|
| -
|
| -DrawDisplayItemListOp::~DrawDisplayItemListOp() = default;
|
| -
|
| -DrawImageOp::DrawImageOp(const PaintImage& image,
|
| - SkScalar left,
|
| - SkScalar top,
|
| - const PaintFlags* flags)
|
| - : image(image),
|
| - left(left),
|
| - top(top),
|
| - flags(flags ? *flags : PaintFlags()) {}
|
| -
|
| -DrawImageOp::~DrawImageOp() = default;
|
| -
|
| -DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
|
| - const SkRect& src,
|
| - const SkRect& dst,
|
| - const PaintFlags* flags,
|
| - PaintCanvas::SrcRectConstraint constraint)
|
| - : image(image),
|
| - flags(flags ? *flags : PaintFlags()),
|
| - src(src),
|
| - dst(dst),
|
| - constraint(constraint) {}
|
| -
|
| -DrawImageRectOp::~DrawImageRectOp() = default;
|
| -
|
| -DrawPosTextOp::DrawPosTextOp(size_t bytes,
|
| - size_t count,
|
| - const PaintFlags& flags)
|
| - : PaintOpWithDataArray(bytes, count), flags(flags) {}
|
| -
|
| -DrawPosTextOp::~DrawPosTextOp() = default;
|
| -
|
| -DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
|
| - : record(std::move(record)) {}
|
| -
|
| -DrawRecordOp::~DrawRecordOp() = default;
|
| -
|
| -size_t DrawRecordOp::AdditionalBytesUsed() const {
|
| - return record->approximateBytesUsed();
|
| -}
|
| -
|
| -DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
|
| - SkScalar x,
|
| - SkScalar y,
|
| - const PaintFlags& flags)
|
| - : blob(std::move(blob)), x(x), y(y), flags(flags) {}
|
| -
|
| -DrawTextBlobOp::~DrawTextBlobOp() = default;
|
| -
|
| -PaintOpBuffer::PaintOpBuffer() : cull_rect_(SkRect::MakeEmpty()) {}
|
| -
|
| -PaintOpBuffer::PaintOpBuffer(const SkRect& cull_rect) : cull_rect_(cull_rect) {}
|
| -
|
| -PaintOpBuffer::~PaintOpBuffer() {
|
| - Reset();
|
| -}
|
| -
|
| -void PaintOpBuffer::Reset() {
|
| - for (auto* op : Iterator(this)) {
|
| - auto func = g_destructor_functions[op->type];
|
| - if (func)
|
| - func(op);
|
| - }
|
| -
|
| - // Leave data_ allocated, reserved_ unchanged.
|
| - used_ = 0;
|
| - op_count_ = 0;
|
| - num_slow_paths_ = 0;
|
| -}
|
| -
|
| -void PaintOpBuffer::playback(SkCanvas* canvas) const {
|
| - // TODO(enne): a PaintRecord that contains a SetMatrix assumes that the
|
| - // SetMatrix is local to that PaintRecord itself. Said differently, if you
|
| - // translate(x, y), then draw a paint record with a SetMatrix(identity),
|
| - // the translation should be preserved instead of clobbering the top level
|
| - // transform. This could probably be done more efficiently.
|
| - SkMatrix original = canvas->getTotalMatrix();
|
| -
|
| - for (Iterator iter(this); iter; ++iter) {
|
| - // Optimize out save/restores or save/draw/restore that can be a single
|
| - // draw. See also: similar code in SkRecordOpts and cc's DisplayItemList.
|
| - // TODO(enne): consider making this recursive?
|
| - const PaintOp* op = *iter;
|
| - if (op->GetType() == PaintOpType::SaveLayerAlpha) {
|
| - const PaintOp* second = iter.peek1();
|
| - if (second) {
|
| - if (second->GetType() == PaintOpType::Restore) {
|
| - ++iter;
|
| - continue;
|
| - }
|
| - if (second->IsDrawOp()) {
|
| - const PaintOp* third = iter.peek2();
|
| - if (third && third->GetType() == PaintOpType::Restore) {
|
| - const SaveLayerAlphaOp* save_op =
|
| - static_cast<const SaveLayerAlphaOp*>(op);
|
| - second->RasterWithAlpha(canvas, save_op->alpha);
|
| - ++iter;
|
| - ++iter;
|
| - continue;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - // TODO(enne): skip SaveLayer followed by restore with nothing in
|
| - // between, however SaveLayer with image filters on it (or maybe
|
| - // other PaintFlags options) are not a noop. Figure out what these
|
| - // are so we can skip them correctly.
|
| -
|
| - op->Raster(canvas, original);
|
| - }
|
| -}
|
| -
|
| -void PaintOpBuffer::playback(SkCanvas* canvas,
|
| - SkPicture::AbortCallback* callback) const {
|
| - // The abort callback is only used for analysis, in general, so
|
| - // this playback code can be more straightforward and not do the
|
| - // optimizations in the other function.
|
| - if (!callback) {
|
| - playback(canvas);
|
| - return;
|
| - }
|
| -
|
| - SkMatrix original = canvas->getTotalMatrix();
|
| -
|
| - // TODO(enne): ideally callers would just iterate themselves and we
|
| - // can remove the entire notion of an abort callback.
|
| - for (auto* op : Iterator(this)) {
|
| - op->Raster(canvas, original);
|
| - if (callback && callback->abort())
|
| - return;
|
| - }
|
| -}
|
| -
|
| -void PaintOpBuffer::ShrinkToFit() {
|
| - if (!used_ || used_ == reserved_)
|
| - return;
|
| - data_.realloc(used_);
|
| - reserved_ = used_;
|
| -}
|
| -
|
| -} // namespace cc
|
|
|