Store content streams in an SkStream instead of an SkString (64k size limit).

Review URL: http://codereview.appspot.com/4272070

git-svn-id: http://skia.googlecode.com/svn/trunk@1011 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
vandebo@chromium.org 2011-03-28 19:03:50 +00:00
parent 94f6a730bb
commit cae5fba82e
7 changed files with 127 additions and 115 deletions

View File

@ -19,7 +19,7 @@
#include "SkRefCnt.h"
#include "SkDevice.h"
#include "SkString.h"
#include "SkStream.h"
#include "SkPaint.h"
#include "SkPath.h"
@ -175,7 +175,7 @@ private:
struct GraphicStackEntry fGraphicStack[3];
int fGraphicStackIndex;
SkString fContent;
SkDynamicMemoryWStream fContent;
void updateGSFromPaint(const SkPaint& newPaint, bool forText);
void updateFont(const SkPaint& paint, uint16_t glyphID);

View File

@ -151,7 +151,7 @@ public:
explicit SkPDFScalar(SkScalar value);
virtual ~SkPDFScalar();
static void Append(SkScalar value, SkString* string);
static void Append(SkScalar value, SkWStream* stream);
// The SkPDFObject interface.
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,

View File

@ -32,19 +32,19 @@ class SkPDFArray;
class SkPDFUtils {
public:
static SkPDFArray* MatrixToArray(const SkMatrix& matrix);
static void MoveTo(SkScalar x, SkScalar y, SkString* content);
static void AppendLine(SkScalar x, SkScalar y, SkString* content);
static void MoveTo(SkScalar x, SkScalar y, SkWStream* content);
static void AppendLine(SkScalar x, SkScalar y, SkWStream* content);
static void AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
SkScalar ctl2X, SkScalar ctl2Y,
SkScalar dstX, SkScalar dstY, SkString* content);
SkScalar dstX, SkScalar dstY, SkWStream* content);
static void AppendRectangle(SkScalar x, SkScalar y, SkScalar w, SkScalar h,
SkString* content);
static void EmitPath(const SkPath& path, SkString* content);
static void ClosePath(SkString* content);
SkWStream* content);
static void EmitPath(const SkPath& path, SkWStream* content);
static void ClosePath(SkWStream* content);
static void PaintPath(SkPaint::Style style, SkPath::FillType fill,
SkString* content);
static void StrokePath(SkString* content);
SkWStream* content);
static void StrokePath(SkWStream* content);
};
#endif

View File

@ -38,20 +38,18 @@
namespace {
SkString toPDFColor(SkColor color) {
void emitPDFColor(SkColor color, SkWStream* result) {
SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere.
SkScalar colorMax = SkIntToScalar(0xFF);
SkString result;
SkPDFScalar::Append(
SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), &result);
result.append(" ");
SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), result);
result->writeText(" ");
SkPDFScalar::Append(
SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), &result);
result.append(" ");
SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), result);
result->writeText(" ");
SkPDFScalar::Append(
SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), &result);
result.append(" ");
return result;
SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), result);
result->writeText(" ");
}
SkPaint calculateTextPaint(const SkPaint& paint) {
@ -145,7 +143,9 @@ SkPDFDevice::SkPDFDevice(int width, int height, OriginTransform flipOrigin)
fGraphicStack[0].fTransform.reset();
if (flipOrigin == kFlip_OriginTransform) {
fContent.printf("1 0 0 -1 0 %d cm\n", fHeight);
fContent.writeText("1 0 0 -1 0 ");
fContent.writeDecAsText(fHeight);
fContent.writeText(" cm\n");
}
}
@ -175,9 +175,9 @@ void SkPDFDevice::setMatrixClip(const SkMatrix& matrix,
NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType,
false);
if (clipFill == SkPath::kEvenOdd_FillType)
fContent.append("W* n ");
fContent.writeText("W* n ");
else
fContent.append("W n ");
fContent.writeText("W n ");
}
fGraphicStack[fGraphicStackIndex].fClip = region;
@ -339,7 +339,7 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
alignText(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y, widthPtr);
fContent.append("BT\n");
fContent.writeText("BT\n");
setTextTransform(x, y, textPaint.getTextSkewX());
size_t consumedGlyphCount = 0;
while (numGlyphs > consumedGlyphCount) {
@ -348,13 +348,14 @@ void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
size_t availableGlyphs =
font->glyphsToPDFFontEncoding(glyphIDs + consumedGlyphCount,
numGlyphs - consumedGlyphCount);
fContent.append(SkPDFString::formatString(glyphIDs + consumedGlyphCount,
availableGlyphs,
font->multiByteGlyphs()));
SkString encodedString =
SkPDFString::formatString(glyphIDs + consumedGlyphCount,
availableGlyphs, font->multiByteGlyphs());
fContent.writeText(encodedString.c_str());
consumedGlyphCount += availableGlyphs;
fContent.append(" Tj\n");
fContent.writeText(" Tj\n");
}
fContent.append("ET\n");
fContent.writeText("ET\n");
// Draw underline and/or strikethrough if the paint has them.
// drawPosText() and drawTextOnPath() don't draw underline or strikethrough
@ -402,7 +403,7 @@ void SkPDFDevice::drawPosText(const SkDraw&, const void* text, size_t len,
}
SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
fContent.append("BT\n");
fContent.writeText("BT\n");
updateFont(textPaint, glyphIDs[0]);
for (size_t i = 0; i < numGlyphs; i++) {
SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont;
@ -416,11 +417,13 @@ void SkPDFDevice::drawPosText(const SkDraw&, const void* text, size_t len,
SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
alignText(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y, NULL);
setTextTransform(x, y, textPaint.getTextSkewX());
fContent.append(SkPDFString::formatString(&encodedValue, 1,
font->multiByteGlyphs()));
fContent.append(" Tj\n");
SkString encodedString =
SkPDFString::formatString(&encodedValue, 1,
font->multiByteGlyphs());
fContent.writeText(encodedString.c_str());
fContent.writeText(" Tj\n");
}
fContent.append("ET\n");
fContent.writeText("ET\n");
}
void SkPDFDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
@ -454,9 +457,9 @@ void SkPDFDevice::drawDevice(const SkDraw& d, SkDevice* device, int x, int y,
SkPDFFormXObject* xobject = new SkPDFFormXObject(pdfDevice);
fXObjectResources.push(xobject); // Transfer reference.
fContent.append("/X");
fContent.appendS32(fXObjectResources.count() - 1);
fContent.append(" Do\n");
fContent.writeText("/X");
fContent.writeDecAsText(fXObjectResources.count() - 1);
fContent.writeText(" Do\n");
setTransform(curTransform);
}
@ -571,9 +574,9 @@ SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
}
SkStream* SkPDFDevice::content() const {
size_t offset = fContent.size();
size_t offset = fContent.getOffset();
char* data = (char*)sk_malloc_throw(offset + fGraphicStackIndex * 2);
memcpy(data, fContent.c_str(), offset);
fContent.copyTo(data);
for (int i = 0; i < fGraphicStackIndex; i++) {
data[offset++] = 'Q';
data[offset++] = '\n';
@ -637,8 +640,11 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
fShaderResources.push(pdfShader.get());
pdfShader->ref();
}
fContent.appendf("/Pattern CS /Pattern cs /P%d SCN /P%d scn\n",
resourceIndex, resourceIndex);
fContent.writeText("/Pattern CS /Pattern cs /P");
fContent.writeDecAsText(resourceIndex);
fContent.writeText(" SCN /P");
fContent.writeDecAsText(resourceIndex);
fContent.writeText(" scn\n");
fGraphicStack[fGraphicStackIndex].fShader = pdfShader.get();
}
} else {
@ -646,11 +652,10 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
newColor = SkColorSetA(newColor, 0xFF);
if (fGraphicStack[fGraphicStackIndex].fShader ||
fGraphicStack[fGraphicStackIndex].fColor != newColor) {
SkString colorString = toPDFColor(newColor);
fContent.append(colorString);
fContent.append("RG ");
fContent.append(colorString);
fContent.append("rg\n");
emitPDFColor(newColor, &fContent);
fContent.writeText("RG ");
emitPDFColor(newColor, &fContent);
fContent.writeText("rg\n");
fGraphicStack[fGraphicStackIndex].fColor = newColor;
fGraphicStack[fGraphicStackIndex].fShader = NULL;
}
@ -669,9 +674,9 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
fGraphicStateResources.push(newGraphicState.get());
newGraphicState->ref();
}
fContent.append("/G");
fContent.appendS32(resourceIndex);
fContent.append(" gs\n");
fContent.writeText("/G");
fContent.writeDecAsText(resourceIndex);
fContent.writeText(" gs\n");
fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get();
}
@ -681,7 +686,7 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
SkScalar scale = newPaint.getTextScaleX();
SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100));
SkPDFScalar::Append(pdfScale, &fContent);
fContent.append(" Tz\n");
fContent.writeText(" Tz\n");
fGraphicStack[fGraphicStackIndex].fTextScaleX = scale;
}
@ -692,8 +697,8 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) {
enum_must_match_value);
SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
enum_must_match_value);
fContent.appendS32(newPaint.getStyle());
fContent.append(" Tr\n");
fContent.writeDecAsText(newPaint.getStyle());
fContent.writeText(" Tr\n");
fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle();
}
}
@ -706,11 +711,11 @@ void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) {
fGraphicStack[fGraphicStackIndex].fFont->typeface() != typeface ||
!fGraphicStack[fGraphicStackIndex].fFont->hasGlyph(glyphID)) {
int fontIndex = getFontResourceIndex(typeface, glyphID);
fContent.append("/F");
fContent.appendS32(fontIndex);
fContent.append(" ");
fContent.writeText("/F");
fContent.writeDecAsText(fontIndex);
fContent.writeText(" ");
SkPDFScalar::Append(paint.getTextSize(), &fContent);
fContent.append(" Tf\n");
fContent.writeText(" Tf\n");
fGraphicStack[fGraphicStackIndex].fTextSize = paint.getTextSize();
fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex];
}
@ -730,27 +735,27 @@ int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) {
void SkPDFDevice::pushGS() {
SkASSERT(fGraphicStackIndex < 2);
fContent.append("q\n");
fContent.writeText("q\n");
fGraphicStackIndex++;
fGraphicStack[fGraphicStackIndex] = fGraphicStack[fGraphicStackIndex - 1];
}
void SkPDFDevice::popGS() {
SkASSERT(fGraphicStackIndex > 0);
fContent.append("Q\n");
fContent.writeText("Q\n");
fGraphicStackIndex--;
}
void SkPDFDevice::setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX) {
// Flip the text about the x-axis to account for origin swap and include
// the passed parameters.
fContent.append("1 0 ");
fContent.writeText("1 0 ");
SkPDFScalar::Append(0 - textSkewX, &fContent);
fContent.append(" -1 ");
fContent.writeText(" -1 ");
SkPDFScalar::Append(x, &fContent);
fContent.append(" ");
fContent.writeText(" ");
SkPDFScalar::Append(y, &fContent);
fContent.append(" Tm\n");
fContent.writeText(" Tm\n");
}
void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
@ -777,9 +782,9 @@ void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
updateGSFromPaint(paint, false);
fXObjectResources.push(image); // Transfer reference.
fContent.append("/X");
fContent.appendS32(fXObjectResources.count() - 1);
fContent.append(" Do\n");
fContent.writeText("/X");
fContent.writeDecAsText(fXObjectResources.count() - 1);
fContent.writeText(" Do\n");
setTransform(curTransform);
}
@ -807,9 +812,9 @@ SkMatrix SkPDFDevice::setTransform(const SkMatrix& m) {
SkAssertResult(m.pdfTransform(transform));
for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
SkPDFScalar::Append(transform[i], &fContent);
fContent.append(" ");
fContent.writeText(" ");
}
fContent.append("cm\n");
fContent.writeText("cm\n");
fGraphicStack[fGraphicStackIndex].fTransform = m;
return old;

View File

@ -236,11 +236,18 @@ SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) {
}
void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box,
SkString* content) {
SkWStream* content) {
// Specify width and bounding box for the glyph.
SkPDFScalar::Append(width, content);
content->appendf(" 0 %d %d %d %d d1\n", box.fLeft, box.fTop,
box.fRight, box.fBottom);
content->writeText(" 0 ");
content->writeDecAsText(box.fLeft);
content->writeText(" ");
content->writeDecAsText(box.fTop);
content->writeText(" ");
content->writeDecAsText(box.fRight);
content->writeText(" ");
content->writeDecAsText(box.fBottom);
content->writeText(" d1\n");
}
SkPDFArray* makeFontBBox(
@ -670,7 +677,7 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
glyph.fWidth, glyph.fHeight);
bbox.join(glyphBBox);
SkString content;
SkDynamicMemoryWStream content;
setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox,
&content);
const SkPath* path = cache->findPath(glyph);
@ -679,9 +686,10 @@ void SkPDFFont::populateType3Font(int16_t glyphID) {
SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(),
&content);
}
SkRefPtr<SkStream> glyphStream =
new SkMemoryStream(content.c_str(), content.size(), true);
SkRefPtr<SkMemoryStream> glyphStream = new SkMemoryStream();
glyphStream->unref(); // SkRefPtr and new both took a ref.
glyphStream->setMemoryOwned(content.detach(), content.getOffset());
SkRefPtr<SkPDFStream> glyphDescription =
new SkPDFStream(glyphStream.get());
// SkRefPtr and new both ref()'d charProcs, pass one.

View File

@ -100,32 +100,31 @@ void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
if (indirect)
return emitIndirectObject(stream, catalog);
SkString tmp;
Append(fValue, &tmp);
stream->write(tmp.c_str(), tmp.size());
Append(fValue, stream);
}
// static
void SkPDFScalar::Append(SkScalar value, SkString* string) {
void SkPDFScalar::Append(SkScalar value, SkWStream* stream) {
// The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and
// +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31).
// When using floats that are outside the whole value range, we can use
// integers instead.
#if defined(SK_SCALAR_IS_FIXED)
string->appendScalar(value);
stream->wrieScalarAsText(value);
return;
#endif // SK_SCALAR_IS_FIXED
#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
if (value > 32767 || value < -32767) {
string->appendS32(SkScalarRound(value));
stream->writeDecAsText(SkScalarRound(value));
return;
}
char buffer[SkStrAppendScalar_MaxSize];
char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value));
string->append(buffer, end - buffer);
stream->write(buffer, end - buffer);
return;
#endif // !SK_ALLOW_LARGE_PDF_SCALARS
@ -134,12 +133,12 @@ void SkPDFScalar::Append(SkScalar value, SkString* string) {
// no more precise than an int. (Plus PDF doesn't support scientific
// notation, so this clamps to SK_Max/MinS32).
if (value > (1 << 24) || value < -(1 << 24)) {
string->appendS32(value);
stream->writeDecAsText(value);
return;
}
// Continue to enforce the PDF limits for small floats.
if (value < 1.0f/65536 && value > -1.0f/65536) {
string->appendS32(0);
stream->writeDecAsText(0);
return;
}
// SkStrAppendFloat might still use scientific notation, so use snprintf
@ -154,7 +153,7 @@ void SkPDFScalar::Append(SkScalar value, SkString* string) {
if (buffer[len - 1] == '.') {
buffer[len - 1] = '\0';
}
string->append(buffer);
stream->writeText(buffer);
return;
#endif // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS
}

View File

@ -17,6 +17,7 @@
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPDFUtils.h"
#include "SkStream.h"
#include "SkString.h"
#include "SkPDFTypes.h"
@ -34,59 +35,59 @@ SkPDFArray* SkPDFUtils::MatrixToArray(const SkMatrix& matrix) {
}
// static
void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkString* content) {
void SkPDFUtils::MoveTo(SkScalar x, SkScalar y, SkWStream* content) {
SkPDFScalar::Append(x, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(y, content);
content->append(" m\n");
content->writeText(" m\n");
}
// static
void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkString* content) {
void SkPDFUtils::AppendLine(SkScalar x, SkScalar y, SkWStream* content) {
SkPDFScalar::Append(x, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(y, content);
content->append(" l\n");
content->writeText(" l\n");
}
// static
void SkPDFUtils::AppendCubic(SkScalar ctl1X, SkScalar ctl1Y,
SkScalar ctl2X, SkScalar ctl2Y,
SkScalar dstX, SkScalar dstY, SkString* content) {
SkScalar dstX, SkScalar dstY, SkWStream* content) {
SkString cmd("y\n");
SkPDFScalar::Append(ctl1X, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(ctl1Y, content);
content->append(" ");
content->writeText(" ");
if (ctl2X != dstX || ctl2Y != dstY) {
cmd.set("c\n");
SkPDFScalar::Append(ctl2X, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(ctl2Y, content);
content->append(" ");
content->writeText(" ");
}
SkPDFScalar::Append(dstX, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(dstY, content);
content->append(" ");
content->append(cmd);
content->writeText(" ");
content->writeText(cmd.c_str());
}
// static
void SkPDFUtils::AppendRectangle(SkScalar x, SkScalar y,
SkScalar w, SkScalar h, SkString* content) {
SkScalar w, SkScalar h, SkWStream* content) {
SkPDFScalar::Append(x, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(y, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(w, content);
content->append(" ");
content->writeText(" ");
SkPDFScalar::Append(h, content);
content->append(" re\n");
content->writeText(" re\n");
}
// static
void SkPDFUtils::EmitPath(const SkPath& path, SkString* content) {
// static
void SkPDFUtils::EmitPath(const SkPath& path, SkWStream* content) {
SkPoint args[4];
SkPath::Iter iter(path, false);
for (SkPath::Verb verb = iter.next(args);
@ -129,32 +130,31 @@ void SkPDFUtils::EmitPath(const SkPath& path, SkString* content) {
}
// static
void SkPDFUtils::ClosePath(SkString* content) {
content->append("h\n");
void SkPDFUtils::ClosePath(SkWStream* content) {
content->writeText("h\n");
}
// static
void SkPDFUtils::PaintPath(SkPaint::Style style, SkPath::FillType fill,
SkString* content) {
SkWStream* content) {
if (style == SkPaint::kFill_Style)
content->append("f");
content->writeText("f");
else if (style == SkPaint::kStrokeAndFill_Style)
content->append("B");
content->writeText("B");
else if (style == SkPaint::kStroke_Style)
content->append("S");
content->writeText("S");
if (style != SkPaint::kStroke_Style) {
// Not supported yet.
NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false);
NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false);
if (fill == SkPath::kEvenOdd_FillType)
content->append("*");
content->writeText("*");
}
content->append("\n");
content->writeText("\n");
}
// static
void SkPDFUtils::StrokePath(SkString* content) {
void SkPDFUtils::StrokePath(SkWStream* content) {
SkPDFUtils::PaintPath(
SkPaint::kStroke_Style, SkPath::kWinding_FillType, content);
}