SkDocument base for pdf, xps, etc.

R=scroggo@google.com

Review URL: https://codereview.chromium.org/16660002

git-svn-id: http://skia.googlecode.com/svn/trunk@9476 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2013-06-07 20:30:16 +00:00
parent 99d43ffcfb
commit 99ac02bb70
7 changed files with 331 additions and 18 deletions

View File

@ -186,6 +186,8 @@
'<(skia_src_path)/core/SkWriter32.cpp',
'<(skia_src_path)/core/SkXfermode.cpp',
'<(skia_src_path)/doc/SkDocument.cpp',
'<(skia_src_path)/image/SkDataPixelRef.cpp',
'<(skia_src_path)/image/SkImage.cpp',
'<(skia_src_path)/image/SkImagePriv.cpp',

View File

@ -47,6 +47,8 @@
'../src/pdf/SkPDFUtils.cpp',
'../src/pdf/SkPDFUtils.h',
'../src/pdf/SkTSet.h',
'../src/doc/SkDocument_PDF.cpp',
],
# This section makes all targets that depend on this target
# #define SK_SUPPORT_PDF and have access to the pdf header files.

View File

@ -64,6 +64,7 @@
],
'dependencies': [
'skia_lib.gyp:skia_lib',
'pdf.gyp:pdf',
'flags.gyp:flags',
],
},

94
include/core/SkDocument.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkDocument_DEFINED
#define SkDocument_DEFINED
#include "SkRect.h"
#include "SkRefCnt.h"
class SkCanvas;
class SkWStream;
/**
* High-level API for creating a document-based canvas. To use..
*
* 1. Create a document, specifying a stream to store the output.
* 2. For each "page" of content:
* a. canvas = doc->beginPage(...)
* b. draw_my_content(canvas);
* c. doc->endPage();
* 3. Close the document with doc->close().
*/
class SkDocument : public SkRefCnt {
public:
/**
* Create a PDF-backed document, writing the results into a file.
* If there is an error trying to create the doc, returns NULL.
*/
static SkDocument* CreatePDF(const char filename[]);
/**
* Create a PDF-backed document, writing the results into a stream.
* If there is an error trying to create the doc, returns NULL.
*
* The document may write to the stream at anytime during its lifetime,
* until either close() is called or the document is deleted. Once close()
* has been called, and all of the data has been written to the stream,
* if there is a Done proc provided, it will be called with the stream.
* The proc can delete the stream, or whatever it needs to do.
*/
static SkDocument* CreatePDF(SkWStream*, void (*Done)(SkWStream*) = NULL);
/**
* Begin a new page for the document, returning the canvas that will draw
* into the page. The document owns this canvas, and it will go out of
* scope when endPage() or close() is called, or the document is deleted.
*/
SkCanvas* beginPage(SkScalar width, SkScalar height,
const SkRect* content = NULL);
/**
* Call endPage() when the content for the current page has been drawn
* (into the canvas returned by beginPage()). After this call the canvas
* returned by beginPage() will be out-of-scope.
*/
void endPage();
/**
* Call close() when all pages have been drawn. This will close the file
* or stream holding the document's contents. After close() the document
* can no longer add new pages. Deleting the document will automatically
* call close() if need be.
*/
void close();
protected:
SkDocument(SkWStream*, void (*)(SkWStream*));
// note: subclasses must call close() in their destructor, as the base class
// cannot do this for them.
virtual ~SkDocument();
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
const SkRect& content) = 0;
virtual void onEndPage() = 0;
virtual void onClose(SkWStream*) = 0;
enum State {
kBetweenPages_State,
kInPage_State,
kClosed_State
};
State getState() const { return fState; }
private:
SkWStream* fStream;
void (*fDoneProc)(SkWStream*);
State fState;
};
#endif

83
src/doc/SkDocument.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkDocument.h"
#include "SkStream.h"
SkDocument::SkDocument(SkWStream* stream, void (*doneProc)(SkWStream*)) {
fStream = stream; // we do not own this object.
fDoneProc = doneProc;
fState = kBetweenPages_State;
}
SkDocument::~SkDocument() {
this->close();
}
SkCanvas* SkDocument::beginPage(SkScalar width, SkScalar height,
const SkRect* content) {
if (width <= 0 || height <= 0) {
return NULL;
}
SkRect outer = SkRect::MakeWH(width, height);
SkRect inner;
if (content) {
inner = *content;
if (!inner.intersect(outer)) {
return NULL;
}
} else {
inner = outer;
}
for (;;) {
switch (fState) {
case kBetweenPages_State:
fState = kInPage_State;
return this->onBeginPage(width, height, inner);
case kInPage_State:
this->endPage();
break;
case kClosed_State:
return NULL;
}
}
SkASSERT(!"never get here");
return NULL;
}
void SkDocument::endPage() {
if (kInPage_State == fState) {
fState = kBetweenPages_State;
this->onEndPage();
}
}
void SkDocument::close() {
for (;;) {
switch (fState) {
case kBetweenPages_State:
fState = kClosed_State;
this->onClose(fStream);
if (fDoneProc) {
fDoneProc(fStream);
}
// we don't own the stream, but we mark it NULL since we can
// no longer write to it.
fStream = NULL;
return;
case kInPage_State:
this->endPage();
break;
case kClosed_State:
return;
}
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkDocument.h"
#include "SkPDFDocument.h"
#include "SkPDFDevice.h"
class SkDocument_PDF : public SkDocument {
public:
SkDocument_PDF(SkWStream* stream, void (*doneProc)(SkWStream*))
: SkDocument(stream, doneProc) {
fDoc = SkNEW(SkPDFDocument);
fCanvas = NULL;
fDevice = NULL;
}
virtual ~SkDocument_PDF() {
// subclasses must call close() in their destructors
this->close();
}
protected:
virtual SkCanvas* onBeginPage(SkScalar width, SkScalar height,
const SkRect& content) SK_OVERRIDE {
SkASSERT(NULL == fCanvas);
SkASSERT(NULL == fDevice);
SkISize pageS, contentS;
SkMatrix matrix;
pageS.set(SkScalarRoundToInt(width), SkScalarRoundToInt(height));
contentS.set(SkScalarRoundToInt(content.width()),
SkScalarRoundToInt(content.height()));
matrix.setTranslate(content.fLeft, content.fTop);
fDevice = SkNEW_ARGS(SkPDFDevice, (pageS, contentS, matrix));
fCanvas = SkNEW_ARGS(SkCanvas, (fDevice));
return fCanvas;
}
virtual void onEndPage() SK_OVERRIDE {
SkASSERT(fCanvas);
SkASSERT(fDevice);
fCanvas->flush();
fDoc->appendPage(fDevice);
fCanvas->unref();
fDevice->unref();
fCanvas = NULL;
fDevice = NULL;
}
virtual void onClose(SkWStream* stream) SK_OVERRIDE {
SkASSERT(NULL == fCanvas);
SkASSERT(NULL == fDevice);
fDoc->emitPDF(stream);
SkDELETE(fDoc);
fDoc = NULL;
}
private:
SkPDFDocument* fDoc;
SkPDFDevice* fDevice;
SkCanvas* fCanvas;
};
///////////////////////////////////////////////////////////////////////////////
SkDocument* SkDocument::CreatePDF(SkWStream* stream, void (*done)(SkWStream*)) {
return stream ? SkNEW_ARGS(SkDocument_PDF, (stream, done)) : NULL;
}
static void delete_wstream(SkWStream* stream) {
SkDELETE(stream);
}
SkDocument* SkDocument::CreatePDF(const char path[]) {
SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (path));
if (!stream->isValid()) {
SkDELETE(stream);
return NULL;
}
return SkNEW_ARGS(SkDocument_PDF, (stream, delete_wstream));
}

View File

@ -8,22 +8,62 @@
#include "SkCanvas.h"
#include "SkCommandLineFlags.h"
#include "SkData.h"
#include "SkDocument.h"
#include "SkGraphics.h"
#include "SkSurface.h"
#include "SkImage.h"
#include "SkStream.h"
#include "SkString.h"
DEFINE_string2(outFile, o, "skhello.png", "The filename to write the image.");
DEFINE_string2(outFile, o, "skhello", "The filename to write the image.");
DEFINE_string2(text, t, "Hello", "The string to write.");
static void doDraw(SkCanvas* canvas, const SkPaint& paint, const char text[]) {
SkRect bounds;
canvas->getClipBounds(&bounds);
canvas->drawColor(SK_ColorWHITE);
canvas->drawText(text, strlen(text),
bounds.centerX(), bounds.centerY(),
paint);
}
static bool do_surface(int w, int h, const char path[], const char text[],
const SkPaint& paint) {
SkImage::Info info = {
w, h, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
};
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
doDraw(surface->getCanvas(), paint, text);
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
SkAutoDataUnref data(image->encode());
if (NULL == data.get()) {
return false;
}
SkFILEWStream stream(path);
return stream.write(data->data(), data->size());
}
static bool do_document(int w, int h, const char path[], const char text[],
const SkPaint& paint) {
SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(path));
if (doc.get()) {
SkScalar width = SkIntToScalar(w);
SkScalar height = SkIntToScalar(h);
doDraw(doc->beginPage(width, height, NULL), paint, text);
return true;
}
return false;
}
int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
SkCommandLineFlags::SetUsage("");
SkCommandLineFlags::Parse(argc, argv);
SkAutoGraphics ag;
SkString path("skhello.png");
SkString path("skhello");
SkString text("Hello");
if (!FLAGS_outFile.isEmpty()) {
@ -44,24 +84,23 @@ int tool_main(int argc, char** argv) {
int w = SkScalarRound(width) + 30;
int h = SkScalarRound(spacing) + 30;
SkImage::Info info = {
w, h, SkImage::kPMColor_ColorType, SkImage::kPremul_AlphaType
static const struct {
bool (*fProc)(int w, int h, const char path[], const char text[],
const SkPaint&);
const char* fSuffix;
} gRec[] = {
{ do_surface, ".png" },
{ do_document, ".pdf" },
};
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
SkCanvas* canvas = surface->getCanvas();
canvas->drawColor(SK_ColorWHITE);
canvas->drawText(text.c_str(), text.size(),
SkIntToScalar(w)/2, SkIntToScalar(h)*2/3,
paint);
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
SkAutoDataUnref data(image->encode());
if (NULL == data.get()) {
for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
SkString file;
file.printf("%s%s", path.c_str(), gRec[i].fSuffix);
if (!gRec[i].fProc(w, h, file.c_str(), text.c_str(), paint)) {
return -1;
}
SkFILEWStream stream(path.c_str());
return stream.write(data->data(), data->size());
}
return 0;
}
#if !defined SK_BUILD_FOR_IOS