SkPDF: allocate for single Canvas

Change-Id: I852717b30c687c1f2bba38cfa7ab59780b61c1f5
Reviewed-on: https://skia-review.googlesource.com/153100
Auto-Submit: Hal Canary <halcanary@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
diff --git a/src/pdf/SkPDFDocument.cpp b/src/pdf/SkPDFDocument.cpp
index 51f2e79..5fcdd88 100644
--- a/src/pdf/SkPDFDocument.cpp
+++ b/src/pdf/SkPDFDocument.cpp
@@ -7,7 +7,6 @@
 
 #include "SkPDFDocument.h"
 
-#include "SkCanvas.h"
 #include "SkMakeUnique.h"
 #include "SkPDFCanon.h"
 #include "SkPDFDevice.h"
@@ -15,6 +14,8 @@
 #include "SkStream.h"
 #include "SkTo.h"
 
+#include <utility>
+
 SkPDFObjectSerializer::SkPDFObjectSerializer() : fBaseOffset(0), fNextToBeSerialized(0) {}
 
 SkPDFObjectSerializer::~SkPDFObjectSerializer() {
@@ -173,6 +174,12 @@
     return std::move(curNodes[0]);
 }
 
+template<typename T, typename... Args>
+static void reset_object(T* dst, Args&&... args) {
+    dst->~T();
+    new (dst) T(std::forward<Args>(args)...);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 SkPDFDocument::SkPDFDocument(SkWStream* stream,
@@ -192,7 +199,7 @@
 }
 
 SkCanvas* SkPDFDocument::onBeginPage(SkScalar width, SkScalar height) {
-    SkASSERT(!fCanvas.get());  // endPage() was called before this.
+    SkASSERT(fCanvas.imageInfo().dimensions().isZero());
     if (fPages.empty()) {
         // if this is the first page if the document.
         fObjectSerializer.serializeHeader(this->getStream(), fMetadata);
@@ -216,9 +223,9 @@
 
     fPageDevice = sk_make_sp<SkPDFDevice>(pageSize, this);
     fPageDevice->setFlip();  // Only the top-level device needs to be flipped.
-    fCanvas.reset(new SkCanvas(fPageDevice));
-    fCanvas->scale(rasterScale, rasterScale);
-    return fCanvas.get();
+    reset_object(&fCanvas, fPageDevice);
+    fCanvas.scale(rasterScale, rasterScale);
+    return &fCanvas;
 }
 
 static sk_sp<SkPDFArray> calculate_page_size(SkScalar rasterDpi, SkISize size) {
@@ -227,9 +234,9 @@
 }
 
 void SkPDFDocument::onEndPage() {
-    SkASSERT(fCanvas.get());
-    fCanvas->flush();
-    fCanvas.reset(nullptr);
+    SkASSERT(!fCanvas.imageInfo().dimensions().isZero());
+    fCanvas.flush();
+    reset_object(&fCanvas);
     SkASSERT(fPageDevice);
 
     auto page = sk_make_sp<SkPDFDict>("Page");
@@ -258,11 +265,11 @@
 void SkPDFDocument::reset() {
     fObjectSerializer = SkPDFObjectSerializer();
     fCanon = SkPDFCanon();
+    reset_object(&fCanvas);
     fPages = std::vector<sk_sp<SkPDFDict>>();
     fFonts.reset();
     fDests = nullptr;
     fPageDevice = nullptr;
-    fCanvas = nullptr;
     fID = nullptr;
     fXMP = nullptr;
     fMetadata = SkDocument::PDFMetadata();
@@ -412,7 +419,7 @@
 }
 
 void SkPDFDocument::onClose(SkWStream* stream) {
-    SkASSERT(!fCanvas.get());
+    SkASSERT(fCanvas.imageInfo().dimensions().isZero());
     if (fPages.empty()) {
         this->reset();
         return;
diff --git a/src/pdf/SkPDFDocument.h b/src/pdf/SkPDFDocument.h
index 35e65df..2d7be50 100644
--- a/src/pdf/SkPDFDocument.h
+++ b/src/pdf/SkPDFDocument.h
@@ -7,10 +7,11 @@
 #ifndef SkPDFDocument_DEFINED
 #define SkPDFDocument_DEFINED
 
+#include "SkCanvas.h"
 #include "SkDocument.h"
 #include "SkPDFCanon.h"
-#include "SkPDFMetadata.h"
 #include "SkPDFFont.h"
+#include "SkPDFMetadata.h"
 
 class SkPDFDevice;
 
@@ -81,11 +82,11 @@
 private:
     SkPDFObjectSerializer fObjectSerializer;
     SkPDFCanon fCanon;
+    SkCanvas fCanvas;
     std::vector<sk_sp<SkPDFDict>> fPages;
     SkTHashSet<SkPDFFont*> fFonts;
     sk_sp<SkPDFDict> fDests;
     sk_sp<SkPDFDevice> fPageDevice;
-    std::unique_ptr<SkCanvas> fCanvas;
     sk_sp<SkPDFObject> fID;
     sk_sp<SkPDFObject> fXMP;
     SkDocument::PDFMetadata fMetadata;