aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkPaint.h3
-rw-r--r--include/core/SkScalar.h13
-rw-r--r--include/core/SkTypes.h11
-rw-r--r--include/pdf/SkPDFDevice.h9
-rw-r--r--include/pdf/SkPDFFont.h92
-rw-r--r--include/pdf/SkPDFTypes.h15
-rw-r--r--include/utils/SkTextFormatParams.h48
-rw-r--r--src/core/Makefile.am1
-rw-r--r--src/core/SkDraw.cpp5
-rw-r--r--src/core/SkPaint.cpp50
-rw-r--r--src/core/SkScalar.cpp42
-rw-r--r--src/core/core_files.mk1
-rw-r--r--src/pdf/SkPDFDevice.cpp255
-rw-r--r--src/pdf/SkPDFFont.cpp199
-rw-r--r--src/pdf/SkPDFGraphicState.cpp26
-rw-r--r--src/pdf/SkPDFTypes.cpp57
-rw-r--r--src/pdf/pdf_files.mk1
-rw-r--r--src/ports/SkThread_win.cpp15
18 files changed, 719 insertions, 124 deletions
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 722bc5d851..16411d5886 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -863,9 +863,10 @@ private:
enum {
kCanonicalTextSizeForPaths = 64
};
+ friend class SkAutoGlyphCache;
friend class SkCanvas;
friend class SkDraw;
- friend class SkAutoGlyphCache;
+ friend class SkPDFDevice;
friend class SkTextToPathIter;
};
diff --git a/include/core/SkScalar.h b/include/core/SkScalar.h
index 9130a7cf12..e1a8a33b27 100644
--- a/include/core/SkScalar.h
+++ b/include/core/SkScalar.h
@@ -253,5 +253,18 @@ static inline SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t) {
return A + SkScalarMul(B - A, t);
}
+/** Interpolate along the function described by (keys[length], values[length])
+ for the passed searchKey. SearchKeys outside the range keys[0]-keys[Length]
+ clamp to the min or max value. This function was inspired by a desire
+ to change the multiplier for thickness in fakeBold; therefore it assumes
+ the number of pairs (length) will be small, and a linear search is used.
+ Repeated keys are allowed for discontinuous functions (so long as keys is
+ monotonically increasing), and if key is the value of a repeated scalar in
+ keys, the first one will be used. However, that may change if a binary
+ search is used.
+*/
+SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[],
+ const SkScalar values[], int length);
+
#endif
diff --git a/include/core/SkTypes.h b/include/core/SkTypes.h
index 1f8ecaaf63..85f542136e 100644
--- a/include/core/SkTypes.h
+++ b/include/core/SkTypes.h
@@ -103,6 +103,17 @@ static inline void sk_bzero(void* buffer, size_t size) {
#define SkAssertResult(cond) cond
#endif
+namespace {
+
+template <bool>
+struct SkCompileAssert {
+};
+
+} // namespace
+
+#define SK_COMPILE_ASSERT(expr, msg) \
+ typedef SkCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
///////////////////////////////////////////////////////////////////////
/** Fast type for signed 8 bits. Use for parameter passing and local variables, not for storage
diff --git a/include/pdf/SkPDFDevice.h b/include/pdf/SkPDFDevice.h
index ada2791ec6..b92dc3db2b 100644
--- a/include/pdf/SkPDFDevice.h
+++ b/include/pdf/SkPDFDevice.h
@@ -26,6 +26,7 @@
class SkPDFArray;
class SkPDFDevice;
class SkPDFDict;
+class SkPDFFont;
class SkPDFGraphicState;
class SkPDFObject;
class SkPDFStream;
@@ -124,6 +125,7 @@ private:
SkTDArray<SkPDFGraphicState*> fGraphicStateResources;
SkTDArray<SkPDFObject*> fXObjectResources;
+ SkTDArray<SkPDFFont*> fFontResources;
// In PDF, transforms and clips can only be undone by popping the graphic
// state to before the transform or clip was applied. Because it can be
@@ -138,7 +140,10 @@ private:
// two entries: a clip and then a transform
struct GraphicStackEntry {
SkColor fColor;
+ SkScalar fTextSize;
SkScalar fTextScaleX;
+ SkPaint::Style fTextFill;
+ SkRefPtr<SkPDFFont> fFont;
SkRefPtr<SkPDFGraphicState> fGraphicState;
SkRegion fClip;
SkMatrix fTransform;
@@ -148,7 +153,8 @@ private:
SkString fContent;
- void updateGSFromPaint(const SkPaint& newPaint, SkString* textStaetUpdate);
+ void updateGSFromPaint(const SkPaint& newPaint, bool forText);
+ int getFontResourceIndex(uint32_t fontID);
void moveTo(SkScalar x, SkScalar y);
void appendLine(SkScalar x, SkScalar y);
@@ -162,6 +168,7 @@ private:
void strokePath();
void pushGS();
void popGS();
+ void setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX);
void internalDrawBitmap(const SkMatrix& matrix, const SkBitmap& bitmap,
const SkPaint& paint);
diff --git a/include/pdf/SkPDFFont.h b/include/pdf/SkPDFFont.h
new file mode 100644
index 0000000000..82357ef355
--- /dev/null
+++ b/include/pdf/SkPDFFont.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkPDFFont_DEFINED
+#define SkPDFFont_DEFINED
+
+#include "SkPDFTypes.h"
+#include "SkTDArray.h"
+#include "SkThread.h"
+
+class SkPaint;
+
+/** \class SkPDFFont
+ A PDF Object class representing a font. The font may have resources
+ attached to it in order to embed the font. SkPDFFonts are canonicalized
+ so that resource deduplication will only include one copy of a font.
+ This class uses the same pattern as SkPDFGraphicState, a static weak
+ reference to each instantiated class.
+*/
+class SkPDFFont : public SkPDFDict {
+public:
+ virtual ~SkPDFFont();
+
+ virtual void getResources(SkTDArray<SkPDFObject*>* resourceList);
+
+ /* Returns the font ID represented by this class.
+ */
+ uint32_t fontID();
+
+ /** Returns true if this font supports glyph IDs above 255.
+ */
+ bool multiByteGlyphs();
+
+ /** Covert the specified text to glyph IDs, taking into consideration
+ * PDF encodings and return the number of glyphs IDs written.
+ */
+ int textToPDFGlyphs(const void* text, size_t byteLength,
+ const SkPaint& paint, uint16_t* glyphs,
+ size_t glyphsLength) const;
+
+ /** Get the font resource for the passed font ID. The reference count of
+ * the object is incremented and it is the caller's responsibility to
+ * unreference it when done. This is needed to accommodate the weak
+ * reference pattern used when the returned object is new and has no
+ * other references.
+ * @param paint The SkPaint to emulate.
+ */
+ static SkPDFFont* getFontResouceByID(uint32_t fontID);
+
+private:
+ uint32_t fFontID;
+ bool fMultiByteGlyphs;
+
+ SkTDArray<SkPDFObject*> fResources;
+
+ class FontRec {
+ public:
+ SkPDFFont* fFont;
+ uint32_t fFontID;
+
+ bool operator==(const FontRec& b) const;
+ FontRec(SkPDFFont* font, uint32_t fontID);
+ };
+
+ // This should be made a hash table if performance is a problem.
+ static SkTDArray<FontRec>& canonicalFonts();
+ static SkMutex& canonicalFontsMutex();
+
+ SkPDFFont(uint32_t fontID, bool multiByteGlyphs);
+
+ void populateBuiltinFont(const char fontName[]);
+ void populateFont(const char subType[], const char fontName[],
+ int firstChar, int lastChar, int widths[],
+ SkPDFObject* fontDescriptor);
+
+ static int find(uint32_t fontID);
+};
+
+#endif
diff --git a/include/pdf/SkPDFTypes.h b/include/pdf/SkPDFTypes.h
index a281628a23..fc9b62c30a 100644
--- a/include/pdf/SkPDFTypes.h
+++ b/include/pdf/SkPDFTypes.h
@@ -21,6 +21,7 @@
#include "SkScalar.h"
#include "SkString.h"
#include "SkTDArray.h"
+#include "SkTypes.h"
class SkPDFCatalog;
class SkWStream;
@@ -169,6 +170,14 @@ public:
*/
explicit SkPDFString(const char value[]);
explicit SkPDFString(const SkString& value);
+
+ /** Create a PDF string. Maximum length (in bytes) is 65,535.
+ * @param value A string value.
+ * @param len The length of value.
+ * @param wideChars Indicates if the top byte in value is significant and
+ * should be encoded (true) or not (false).
+ */
+ SkPDFString(const uint16_t* value, size_t len, bool wideChars);
virtual ~SkPDFString();
// The SkPDFObject interface.
@@ -176,12 +185,16 @@ public:
bool indirect);
virtual size_t getOutputSize(SkPDFCatalog* catalog, bool indirect);
+ static SkString formatString(const char* input, size_t len);
+ static SkString formatString(const uint16_t* input, size_t len,
+ bool wideChars);
private:
static const size_t kMaxLen = 65535;
const SkString fValue;
- SkString formatString(const SkString& input);
+ static SkString doFormatString(const void* input, size_t len,
+ bool wideInput, bool wideOutput);
};
/** \class SkPDFName
diff --git a/include/utils/SkTextFormatParams.h b/include/utils/SkTextFormatParams.h
new file mode 100644
index 0000000000..3306270788
--- /dev/null
+++ b/include/utils/SkTextFormatParams.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkTextFormatParams_DEFINES
+#define SkTextFormatParams_DEFINES
+
+#include "SkScalar.h"
+#include "SkTypes.h"
+
+// Fraction of the text size to lower a strike through line below the baseline.
+#define kStdStrikeThru_Offset (-SK_Scalar1 * 6 / 21)
+// Fraction of the text size to lower a underline below the baseline.
+#define kStdUnderline_Offset (SK_Scalar1 / 9)
+// Fraction of the text size to use for a strike through or under-line.
+#define kStdUnderline_Thickness (SK_Scalar1 / 18)
+
+// The fraction of text size to embolden fake bold text scales with text size.
+// At 9 points or below, the stroke width is increased by text size / 24.
+// At 36 points and above, it is increased by text size / 32. In between,
+// it is interpolated between those values.
+static const SkScalar kStdFakeBoldInterpKeys[] = {
+ SkIntToScalar(9),
+ SkIntToScalar(36)
+};
+static const SkScalar kStdFakeBoldInterpValues[] = {
+ SK_Scalar1/24,
+ SK_Scalar1/32
+};
+SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kStdFakeBoldInterpKeys) ==
+ SK_ARRAY_COUNT(kStdFakeBoldInterpValues),
+ mismatched_array_size);
+static const int kStdFakeBoldInterpLength =
+ SK_ARRAY_COUNT(kStdFakeBoldInterpKeys);
+
+#endif //SkTextFormatParams_DEFINES
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 05fc9bb119..4adde0a4c1 100644
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -69,6 +69,7 @@ SkRect.cpp \
SkRefCnt.cpp \
SkRegion.cpp \
SkRegion_path.cpp \
+SkScalar.cpp \
SkScalerContext.cpp \
SkScan.cpp \
SkScan_AntiPath.cpp \
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 8671d74d70..eff2b32a4c 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -29,6 +29,7 @@
#include "SkShader.h"
#include "SkStroke.h"
#include "SkTemplatesPriv.h"
+#include "SkTextFormatParams.h"
#include "SkUtils.h"
#include "SkAutoKern.h"
@@ -1224,10 +1225,6 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
}
}
-#define kStdStrikeThru_Offset (-SK_Scalar1 * 6 / 21)
-#define kStdUnderline_Offset (SK_Scalar1 / 9)
-#define kStdUnderline_Thickness (SK_Scalar1 / 18)
-
static void draw_paint_rect(const SkDraw* draw, const SkPaint& paint,
const SkRect& r, SkScalar textSize) {
if (paint.getStyle() == SkPaint::kFill_Style) {
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 21b7534f9b..43a6892049 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -23,8 +23,10 @@
#include "SkPathEffect.h"
#include "SkRasterizer.h"
#include "SkShader.h"
+#include "SkScalar.h"
#include "SkScalerContext.h"
#include "SkStroke.h"
+#include "SkTextFormatParams.h"
#include "SkTypeface.h"
#include "SkXfermode.h"
#include "SkAutoKern.h"
@@ -1180,49 +1182,6 @@ static void add_flattenable(SkDescriptor* desc, uint32_t tag,
buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
}
-/*
- * interpolates to find the right value for key, in the function represented by the 'length' number of pairs: (keys[i], values[i])
- inspired by a desire to change the multiplier for thickness in fakebold
- therefore, i assumed number of pairs (length) will be small, so a linear search is sufficient
- repeated keys are allowed for discontinuous functions (so long as keys is monotonically increasing), and if
- key is the value of a repeated scalar in keys, the first one will be used
- - this may change if a binary search is used
- - also, this ensures that there is no divide by zero (an assert also checks for that)
-*/
-static SkScalar interpolate(SkScalar key, const SkScalar keys[], const SkScalar values[], int length)
-{
-
- SkASSERT(length > 0);
- SkASSERT(keys != NULL);
- SkASSERT(values != NULL);
-#ifdef SK_DEBUG
- for (int i = 1; i < length; i++)
- SkASSERT(keys[i] >= keys[i-1]);
-#endif
- int right = 0;
- while (right < length && key > keys[right])
- right++;
- //could use sentinal values to eliminate conditionals
- //i assume i am not in control of input values, so i want to make it simple
- if (length == right)
- return values[length-1];
- if (0 == right)
- return values[0];
- //otherwise, we interpolate between right-1 and right
- SkScalar rVal = values[right];
- SkScalar lVal = values[right-1];
- SkScalar rightKey = keys[right];
- SkScalar leftKey = keys[right-1];
- SkASSERT(rightKey != leftKey);
- //fractional amount which we will multiply by the difference in the left value and right value
- SkScalar fract = SkScalarDiv(key-leftKey,rightKey-leftKey);
- return lVal + SkScalarMul(fract, rVal-lVal);
-}
-
-//used for interpolating in fakeBold
-static const SkScalar pointSizes[] = { SkIntToScalar(9), SkIntToScalar(36) };
-static const SkScalar multipliers[] = { SK_Scalar1/24, SK_Scalar1/32 };
-
static SkMask::Format computeMaskFormat(const SkPaint& paint)
{
uint32_t flags = paint.getFlags();
@@ -1284,7 +1243,10 @@ void SkScalerContext::MakeRec(const SkPaint& paint,
#ifdef SK_USE_FREETYPE_EMBOLDEN
flags |= SkScalerContext::kEmbolden_Flag;
#else
- SkScalar fakeBoldScale = interpolate(paint.getTextSize(), pointSizes, multipliers, 2);
+ SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(),
+ kStdFakeBoldInterpKeys,
+ kStdFakeBoldInterpValues,
+ kStdFakeBoldInterpLength);
SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
if (style == SkPaint::kFill_Style)
diff --git a/src/core/SkScalar.cpp b/src/core/SkScalar.cpp
new file mode 100644
index 0000000000..c6755d1d3c
--- /dev/null
+++ b/src/core/SkScalar.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include "SkScalar.h"
+
+SkScalar SkScalarInterpFunc(SkScalar searchKey, const SkScalar keys[],
+ const SkScalar values[], int length) {
+ SkASSERT(length > 0);
+ SkASSERT(keys != NULL);
+ SkASSERT(values != NULL);
+#ifdef SK_DEBUG
+ for (int i = 1; i < length; i++)
+ SkASSERT(keys[i] >= keys[i-1]);
+#endif
+ int right = 0;
+ while (right < length && searchKey > keys[right])
+ right++;
+ // Could use sentinel values to eliminate conditionals, but since the
+ // tables are taken as input, a simpler format is better.
+ if (length == right)
+ return values[length-1];
+ if (0 == right)
+ return values[0];
+ // Otherwise, interpolate between right - 1 and right.
+ SkScalar rightKey = keys[right];
+ SkScalar leftKey = keys[right-1];
+ SkScalar fract = SkScalarDiv(searchKey-leftKey,rightKey-leftKey);
+ return SkScalarInterp(values[right-1], values[right], fract);
+}
diff --git a/src/core/core_files.mk b/src/core/core_files.mk
index d5cdf39a1c..e84365a7cb 100644
--- a/src/core/core_files.mk
+++ b/src/core/core_files.mk
@@ -72,6 +72,7 @@ SOURCE := \
SkRefCnt.cpp \
SkRegion.cpp \
SkRegion_path.cpp \
+ SkScalar.cpp \
SkScalerContext.cpp \
SkScan.cpp \
SkScan_AntiPath.cpp \
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index e9625cf6a6..cc65413328 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -17,15 +17,20 @@
#include "SkPDFDevice.h"
#include "SkColor.h"
+#include "SkGlyphCache.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkPDFImage.h"
#include "SkPDFGraphicState.h"
+#include "SkPDFFont.h"
#include "SkPDFFormXObject.h"
#include "SkPDFTypes.h"
#include "SkPDFStream.h"
#include "SkRect.h"
#include "SkString.h"
+#include "SkTextFormatParams.h"
+#include "SkTypeface.h"
+#include "SkTypes.h"
#define NOT_IMPLEMENTED(condition, assert) \
do { \
@@ -55,6 +60,60 @@ SkString toPDFColor(SkColor color) {
return result;
}
+SkPaint calculateTextPaint(const SkPaint& paint) {
+ SkPaint result = paint;
+ if (result.isFakeBoldText()) {
+ SkScalar fakeBoldScale = SkScalarInterpFunc(result.getTextSize(),
+ kStdFakeBoldInterpKeys,
+ kStdFakeBoldInterpValues,
+ kStdFakeBoldInterpLength);
+ SkScalar width = SkScalarMul(result.getTextSize(), fakeBoldScale);
+ if (result.getStyle() == SkPaint::kFill_Style)
+ result.setStyle(SkPaint::kStrokeAndFill_Style);
+ else
+ width += result.getStrokeWidth();
+ result.setStrokeWidth(width);
+ }
+ return result;
+}
+
+// Stolen from measure_text in SkDraw.cpp and then tweaked.
+void alignText(SkDrawCacheProc glyphCacheProc, const SkPaint& paint,
+ const uint16_t* glyphs, size_t len, SkScalar* x, SkScalar* y,
+ SkScalar* width) {
+ if (paint.getTextAlign() == SkPaint::kLeft_Align && width == NULL)
+ return;
+
+ SkMatrix ident;
+ ident.reset();
+ SkAutoGlyphCache autoCache(paint, &ident);
+ SkGlyphCache* cache = autoCache.getCache();
+
+ const char* start = (char*)glyphs;
+ const char* stop = (char*)(glyphs + len);
+ SkFixed xAdv = 0, yAdv = 0;
+
+ // TODO(vandebo) This probably needs to take kerning into account.
+ while (start < stop) {
+ const SkGlyph& glyph = glyphCacheProc(cache, &start, 0, 0);
+ xAdv += glyph.fAdvanceX;
+ yAdv += glyph.fAdvanceY;
+ };
+ if (width)
+ *width = SkFixedToScalar(xAdv);
+ if (paint.getTextAlign() == SkPaint::kLeft_Align)
+ return;
+
+ SkScalar xAdj = SkFixedToScalar(xAdv);
+ SkScalar yAdj = SkFixedToScalar(yAdv);
+ if (paint.getTextAlign() == SkPaint::kCenter_Align) {
+ xAdj = SkScalarHalf(xAdj);
+ yAdj = SkScalarHalf(yAdj);
+ }
+ *x = *x - xAdj;
+ *y = *y - yAdj;
+}
+
} // namespace
////////////////////////////////////////////////////////////////////////////////
@@ -70,7 +129,9 @@ SkPDFDevice::SkPDFDevice(int width, int height)
fHeight(height),
fGraphicStackIndex(0) {
fGraphicStack[0].fColor = SK_ColorBLACK;
+ fGraphicStack[0].fTextSize = SK_ScalarNaN; // This has no default value.
fGraphicStack[0].fTextScaleX = SK_Scalar1;
+ fGraphicStack[0].fTextFill = SkPaint::kFill_Style;
fGraphicStack[0].fClip.setRect(0,0, width, height);
fGraphicStack[0].fTransform.reset();
}
@@ -78,6 +139,7 @@ SkPDFDevice::SkPDFDevice(int width, int height)
SkPDFDevice::~SkPDFDevice() {
fGraphicStateResources.unrefAll();
fXObjectResources.unrefAll();
+ fFontResources.unrefAll();
}
void SkPDFDevice::setMatrixClip(const SkMatrix& matrix,
@@ -113,7 +175,7 @@ void SkPDFDevice::drawPaint(const SkDraw& d, const SkPaint& paint) {
SkPaint newPaint = paint;
newPaint.setStyle(SkPaint::kFill_Style);
- updateGSFromPaint(newPaint, NULL);
+ updateGSFromPaint(newPaint, false);
SkRect all = SkRect::MakeWH(width() + 1, height() + 1);
drawRect(d, all, newPaint);
@@ -128,14 +190,14 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
switch (mode) {
case SkCanvas::kPolygon_PointMode:
- updateGSFromPaint(paint, NULL);
+ updateGSFromPaint(paint, false);
moveTo(points[0].fX, points[0].fY);
for (size_t i = 1; i < count; i++)
appendLine(points[i].fX, points[i].fY);
strokePath();
break;
case SkCanvas::kLines_PointMode:
- updateGSFromPaint(paint, NULL);
+ updateGSFromPaint(paint, false);
for (size_t i = 0; i < count/2; i++) {
moveTo(points[i * 2].fX, points[i * 2].fY);
appendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY);
@@ -144,7 +206,7 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode,
break;
case SkCanvas::kPoints_PointMode:
if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
- updateGSFromPaint(paint, NULL);
+ updateGSFromPaint(paint, false);
for (size_t i = 0; i < count; i++) {
moveTo(points[i].fX, points[i].fY);
strokePath();
@@ -182,7 +244,7 @@ void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r,
drawPath(d, path, noEffectPaint);
return;
}
- updateGSFromPaint(paint, NULL);
+ updateGSFromPaint(paint, false);
// Skia has 0,0 at top left, pdf at bottom left. Do the right thing.
SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop;
@@ -202,7 +264,7 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path,
drawPath(d, noEffectPath, noEffectPaint);
return;
}
- updateGSFromPaint(paint, NULL);
+ updateGSFromPaint(paint, false);
emitPath(path);
paintPath(paint.getStyle(), path.getFillType());
@@ -222,15 +284,77 @@ void SkPDFDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
internalDrawBitmap(matrix, bitmap, paint);
}
-void SkPDFDevice::drawText(const SkDraw&, const void* text, size_t len,
+void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
- NOT_IMPLEMENTED("drawText", true);
+ SkPaint textPaint = calculateTextPaint(paint);
+ updateGSFromPaint(textPaint, true);
+ SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont.get();
+
+ uint16_t glyphs[len];
+ size_t glyphsLength;
+ glyphsLength = font->textToPDFGlyphs(text, len, textPaint, glyphs, len);
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ SkScalar width;
+ SkScalar* widthPtr = NULL;
+ if (textPaint.isUnderlineText() || textPaint.isStrikeThruText())
+ widthPtr = &width;
+
+ SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
+ alignText(glyphCacheProc, textPaint, glyphs, glyphsLength, &x, &y,
+ widthPtr);
+ fContent.append("BT\n");
+ setTextTransform(x, y, textPaint.getTextSkewX());
+ fContent.append(SkPDFString::formatString(glyphs, glyphsLength,
+ font->multiByteGlyphs()));
+ fContent.append(" Tj\nET\n");
+
+ // Draw underline and/or strikethrough if the paint has them.
+ // drawPosText() and drawTextOnPath() don't draw underline or strikethrough
+ // because the raster versions don't. Use paint instead of textPaint
+ // because we may have changed strokeWidth to do fakeBold text.
+ if (paint.isUnderlineText() || paint.isStrikeThruText()) {
+ SkScalar textSize = paint.getTextSize();
+ SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
+
+ if (paint.isUnderlineText()) {
+ SkScalar top = SkScalarMulAdd(textSize, kStdUnderline_Offset, y);
+ SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
+ drawRect(d, r, paint);
+ }
+ if (paint.isStrikeThruText()) {
+ SkScalar top = SkScalarMulAdd(textSize, kStdStrikeThru_Offset, y);
+ SkRect r = SkRect::MakeXYWH(x, top - height, width, height);
+ drawRect(d, r, paint);
+ }
+ }
}
void SkPDFDevice::drawPosText(const SkDraw&, const void* text, size_t len,
const SkScalar pos[], SkScalar constY,
int scalarsPerPos, const SkPaint& paint) {
- NOT_IMPLEMENTED("drawPosText", false);
+ SkASSERT(1 == scalarsPerPos || 2 == scalarsPerPos);
+ SkPaint textPaint = calculateTextPaint(paint);
+ updateGSFromPaint(textPaint, true);
+ SkPDFFont* font = fGraphicStack[fGraphicStackIndex].fFont.get();
+
+ uint16_t glyphs[len];
+ size_t glyphsLength;
+ glyphsLength = font->textToPDFGlyphs(text, len, textPaint, glyphs, len);
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ SkDrawCacheProc glyphCacheProc = textPaint.getDrawCacheProc();
+ fContent.append("BT\n");
+ for (size_t i = 0; i < glyphsLength; i++) {
+ SkScalar x = pos[i * scalarsPerPos];
+ SkScalar y = scalarsPerPos == 1 ? constY : pos[i * scalarsPerPos + 1];
+ alignText(glyphCacheProc, textPaint, glyphs + i, 1, &x, &y, NULL);
+ setTextTransform(x, y, textPaint.getTextSkewX());
+ fContent.append(SkPDFString::formatString(glyphs + i, 1,
+ font->multiByteGlyphs()));
+ fContent.append(" Tj\n");
+ }
+ fContent.append("ET\n");
}
void SkPDFDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
@@ -304,6 +428,35 @@ const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
}
fResourceDict->insert("XObject", xObjects.get());
}
+
+ if (fFontResources.count()) {
+ SkRefPtr<SkPDFDict> fonts = new SkPDFDict();
+ fonts->unref(); // SkRefPtr and new both took a reference.
+ for (int i = 0; i < fFontResources.count(); i++) {
+ SkString nameString("F");
+ nameString.appendS32(i);
+ SkRefPtr<SkPDFName> name = new SkPDFName(nameString);
+ name->unref(); // SkRefPtr and new both took a reference.
+ SkRefPtr<SkPDFObjRef> fontRef =
+ new SkPDFObjRef(fFontResources[i]);
+ fontRef->unref(); // SkRefPtr and new both took a reference.
+ fonts->insert(name.get(), fontRef.get());
+ }
+ fResourceDict->insert("Font", fonts.get());
+ }
+
+ // For compatibility, add all proc sets (only used for output to PS
+ // devices).
+ const char procs[][7] = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
+ SkRefPtr<SkPDFArray> procSets = new SkPDFArray();
+ procSets->unref(); // SkRefPtr and new both took a reference.
+ procSets->reserve(SK_ARRAY_COUNT(procs));
+ for (size_t i = 0; i < SK_ARRAY_COUNT(procs); i++) {
+ SkRefPtr<SkPDFName> entry = new SkPDFName(procs[i]);
+ entry->unref(); // SkRefPtr and new both took a reference.
+ procSets->append(entry.get());
+ }
+ fResourceDict->insert("ProcSet", procSets.get());
}
return fResourceDict;
}
@@ -311,7 +464,8 @@ const SkRefPtr<SkPDFDict>& SkPDFDevice::getResourceDict() {
void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
resourceList->setReserve(resourceList->count() +
fGraphicStateResources.count() +
- fXObjectResources.count());
+ fXObjectResources.count() +
+ fFontResources.count());
for (int i = 0; i < fGraphicStateResources.count(); i++) {
resourceList->push(fGraphicStateResources[i]);
fGraphicStateResources[i]->ref();
@@ -322,6 +476,11 @@ void SkPDFDevice::getResources(SkTDArray<SkPDFObject*>* resourceList) const {
fXObjectResources[i]->ref();
fXObjectResources[i]->getResources(resourceList);
}
+ for (int i = 0; i < fFontResources.count(); i++) {
+ resourceList->push(fFontResources[i]);
+ fFontResources[i]->ref();
+ fFontResources[i]->getResources(resourceList);
+ }
}
SkRefPtr<SkPDFArray> SkPDFDevice::getMediaBox() const {
@@ -358,17 +517,12 @@ SkString SkPDFDevice::content(bool flipOrigin) const {
// TODO(vandebo) handle these cases.
#define PAINTCHECK(x,y) NOT_IMPLEMENTED(newPaint.x() y, false)
-void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint,
- SkString* textStateUpdate) {
+void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint, bool forText) {
PAINTCHECK(getXfermode, != NULL);
PAINTCHECK(getPathEffect, != NULL);
PAINTCHECK(getMaskFilter, != NULL);
PAINTCHECK(getShader, != NULL);
PAINTCHECK(getColorFilter, != NULL);
- PAINTCHECK(isFakeBoldText, == true);
- PAINTCHECK(isUnderlineText, == true);
- PAINTCHECK(isStrikeThruText, == true);
- PAINTCHECK(getTextSkewX, != 0);
SkRefPtr<SkPDFGraphicState> newGraphicState =
SkPDFGraphicState::getGraphicStateForPaint(newPaint);
@@ -400,17 +554,58 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint,
fGraphicStack[fGraphicStackIndex].fColor = newColor;
}
- if (textStateUpdate != NULL &&
- fGraphicStack[fGraphicStackIndex].fTextScaleX !=
- newPaint.getTextScaleX()) {
- SkScalar scale = newPaint.getTextScaleX();
- SkScalar pdfScale = scale * 100;
- textStateUpdate->appendScalar(pdfScale);
- textStateUpdate->append(" Tz\n");
- fGraphicStack[fGraphicStackIndex].fTextScaleX = scale;
+ if (forText) {
+ uint32_t fontID = SkTypeface::UniqueID(newPaint.getTypeface());
+ if (fGraphicStack[fGraphicStackIndex].fTextSize !=
+ newPaint.getTextSize() ||
+ fGraphicStack[fGraphicStackIndex].fFont.get() == NULL ||
+ fGraphicStack[fGraphicStackIndex].fFont->fontID() != fontID) {
+ int fontIndex = getFontResourceIndex(fontID);
+ fContent.append("/F");
+ fContent.appendS32(fontIndex);
+ fContent.append(" ");
+ fContent.appendScalar(newPaint.getTextSize());
+ fContent.append(" Tf\n");
+ fGraphicStack[fGraphicStackIndex].fTextSize =
+ newPaint.getTextSize();
+ fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex];
+ }
+
+ if (fGraphicStack[fGraphicStackIndex].fTextScaleX !=
+ newPaint.getTextScaleX()) {
+ SkScalar scale = newPaint.getTextScaleX();
+ SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100));
+ fContent.appendScalar(pdfScale);
+ fContent.append(" Tz\n");
+ fGraphicStack[fGraphicStackIndex].fTextScaleX = scale;
+ }
+
+ if (fGraphicStack[fGraphicStackIndex].fTextFill !=
+ newPaint.getStyle()) {
+ SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value);
+ SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1,
+ enum_must_match_value);
+ SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2,
+ enum_must_match_value);
+ fContent.appendS32(newPaint.getStyle());
+ fContent.append(" Tr\n");
+ fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle();
+ }
}
}
+int SkPDFDevice::getFontResourceIndex(uint32_t fontID) {
+ SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResouceByID(fontID);
+ newFont->unref(); // getFontResourceByID and SkRefPtr both took a ref.
+ int resourceIndex = fFontResources.find(newFont.get());
+ if (resourceIndex < 0) {
+ resourceIndex = fFontResources.count();
+ fFontResources.push(newFont.get());
+ newFont->ref();
+ }
+ return resourceIndex;
+}
+
void SkPDFDevice::moveTo(SkScalar x, SkScalar y) {
fContent.appendScalar(x);
fContent.append(" ");
@@ -538,6 +733,18 @@ void SkPDFDevice::popGS() {
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.appendScalar(0 - textSkewX);
+ fContent.append(" -1 ");
+ fContent.appendScalar(x);
+ fContent.append(" ");
+ fContent.appendScalar(y);
+ fContent.append(" Tm\n");
+}
+
void SkPDFDevice::internalDrawBitmap(const SkMatrix& matrix,
const SkBitmap& bitmap,
const SkPaint& paint) {
diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp
new file mode 100644
index 0000000000..1bbc53af4e
--- /dev/null
+++ b/src/pdf/SkPDFFont.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkPaint.h"
+#include "SkPDFFont.h"
+#include "SkUtils.h"
+
+namespace {
+
+uint16_t unicharToWinAnsiGlyphID(SkUnichar uniChar) {
+ // TODO(vandebo) Quick hack to get text working. Either finish the
+ // implementation of this, or remove it and use the encoding built into
+ // the real font.
+ if (uniChar < ' ')
+ return 0;
+ if (uniChar < '~')
+ return uniChar;
+ return 0;
+}
+
+}
+
+SkPDFFont::~SkPDFFont() {
+ SkAutoMutexAcquire lock(canonicalFontsMutex());
+ int index = find(fFontID);
+ SkASSERT(index >= 0);
+ canonicalFonts().removeShuffle(index);
+}
+
+void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) {
+ resourceList->setReserve(resourceList->count() + fResources.count());
+ for (int i = 0; i < fResources.count(); i++) {
+ resourceList->push(fResources[i]);
+ fResources[i]->ref();
+ fResources[i]->getResources(resourceList);
+ }
+}
+
+uint32_t SkPDFFont::fontID() {
+ return fFontID;
+}
+
+bool SkPDFFont::multiByteGlyphs() {
+ return fMultiByteGlyphs;
+}
+
+// TODO(vandebo) This function goes or stays with unicharToWinAnsiGlyphID.
+int SkPDFFont::textToPDFGlyphs(const void* text, size_t byteLength,
+ const SkPaint& paint, uint16_t glyphs[],
+ size_t glyphsLength) const {
+ // For a regular, non built-in font, just ask the paint.
+ if (fResources.count() != 0) {
+ SkASSERT(glyphsLength >= byteLength / 2);
+ if (paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding) {
+ memcpy(glyphs, text, byteLength / 2 * 2);
+ return byteLength / 2;
+ } else {
+ return paint.textToGlyphs(text, byteLength, glyphs);
+ }
+ }
+
+ const char* data = (const char*)text;
+ const char* stop = data + byteLength;
+ const uint16_t* data16 = (const uint16_t*)data;
+ const uint16_t* stop16 = (const uint16_t*)stop;
+ uint16_t* gPtr = glyphs;
+ uint16_t* gEnd = glyphs + glyphsLength;
+
+ // For a built-in font (no resources), we may have to undo glyph encoding
+ // before converting to the standard pdf encoding.
+ switch(paint.getTextEncoding()) {
+ case SkPaint::kUTF8_TextEncoding:
+ while (data < stop && gPtr < gEnd)
+ *gPtr++ = unicharToWinAnsiGlyphID(SkUTF8_NextUnichar(&data));
+ SkASSERT(data >= stop);
+ break;
+ case SkPaint::kUTF16_TextEncoding:
+ while (data16 < stop16 && gPtr < gEnd)
+ *gPtr++ = unicharToWinAnsiGlyphID(SkUTF16_NextUnichar(&data16));
+ SkASSERT(data16 >= stop16);
+ break;
+ case SkPaint::kGlyphID_TextEncoding:
+ while (data16 < stop16 && gPtr < gEnd) {
+ SkUnichar buf;
+ paint.glyphsToUnichars(data16++, 1, &buf);
+ *gPtr++ = unicharToWinAnsiGlyphID(buf);
+ }
+ SkASSERT(data16 >= stop16);
+ break;
+ default:
+ SkASSERT(!"Unknown text encoding");
+ break;
+ }
+ return gPtr - glyphs;
+}
+
+// static
+SkPDFFont* SkPDFFont::getFontResouceByID(uint32_t fontID) {
+ SkAutoMutexAcquire lock(canonicalFontsMutex());
+ int index = find(fontID);
+ if (index >= 0) {
+ canonicalFonts()[index].fFont->ref();
+ return canonicalFonts()[index].fFont;
+ }
+
+ // TODO(vandebo) Lookup and create the font. For now, just use the built-in
+ // Helevtica.
+ SkPDFFont* font = new SkPDFFont(fontID, false);
+ font->populateBuiltinFont("Helvetica");
+
+ FontRec newEntry(font, fontID);
+ canonicalFonts().push(newEntry);
+ return font; // Return the reference new SkPDFFont() created.
+}
+
+// static
+SkTDArray<SkPDFFont::FontRec>& SkPDFFont::canonicalFonts() {
+ // This initialization is only thread safe with gcc.
+ static SkTDArray<FontRec> gCanonicalFonts;
+ return gCanonicalFonts;
+}
+
+// static
+SkMutex& SkPDFFont::canonicalFontsMutex() {
+ // This initialization is only thread safe with gcc.
+ static SkMutex gCanonicalFontsMutex;
+ return gCanonicalFontsMutex;
+}
+
+// static
+int SkPDFFont::find(uint32_t fontID) {
+ FontRec search(NULL, fontID);
+ return canonicalFonts().find(search);
+}
+
+SkPDFFont::SkPDFFont(uint32_t fontID, bool multiByteGlyphs)
+ : fFontID(fontID),
+ fMultiByteGlyphs(multiByteGlyphs) {
+}
+
+void SkPDFFont::populateBuiltinFont(const char fontName[]) {
+ SkASSERT(strcmp(fontName, "Time-Roman") == 0 ||
+ strcmp(fontName, "Time-Bold") == 0 ||
+ strcmp(fontName, "Time-Italic") == 0 ||
+ strcmp(fontName, "Time-BoldItalic") == 0 ||
+ strcmp(fontName, "Helvetica") == 0 ||
+ strcmp(fontName, "Helvetica-Bold") == 0 ||
+ strcmp(fontName, "Helvetica-Oblique") == 0 ||
+ strcmp(fontName, "Helvetica-BoldOblique") == 0 ||
+ strcmp(fontName, "Courier") == 0 ||
+ strcmp(fontName, "Courier-Bold") == 0 ||
+ strcmp(fontName, "Courier-Oblique") == 0 ||
+ strcmp(fontName, "Courier-BoldOblique") == 0 ||
+ strcmp(fontName, "Symbol") == 0 ||
+ strcmp(fontName, "ZapfDingbats") == 0);
+
+ SkRefPtr<SkPDFName> type = new SkPDFName("Font");
+ type->unref(); // SkRefPtr and new both took a reference.
+ insert("Type", type.get());
+
+ SkRefPtr<SkPDFName> subType = new SkPDFName("Type1");
+ subType->unref(); // SkRefPtr and new both took a reference.
+ insert("Subtype", subType.get());
+
+ SkRefPtr<SkPDFName> baseFont = new SkPDFName(fontName);
+ baseFont->unref(); // SkRefPtr and new both took a reference.
+ insert("BaseFont", baseFont.get());
+
+ SkRefPtr<SkPDFName> encoding = new SkPDFName("WinAnsiEncoding");
+ encoding->unref(); // SkRefPtr and new both took a reference.
+ insert("Encoding", encoding.get());
+}
+
+void SkPDFFont::populateFont(const char subType[], const char fontName[],
+ int firstChar, int lastChar, int widths[],
+ SkPDFObject* fontDescriptor) {
+}
+
+bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const {
+ return fFontID == b.fFontID;
+}
+
+SkPDFFont::FontRec::FontRec(SkPDFFont* font, uint32_t fontID)
+ : fFont(font),
+ fFontID(fontID) {
+}
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index d0d47b5e6f..1fb62fa199 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -16,7 +16,6 @@
#include "SkPDFGraphicState.h"
#include "SkStream.h"
-#include "SkTypeface.h"
SkPDFGraphicState::~SkPDFGraphicState() {
SkAutoMutexAcquire lock(canonicalPaintsMutex());
@@ -107,24 +106,6 @@ void SkPDFGraphicState::populateDict() {
strokeJoin->unref(); // SkRefPtr and new both took a reference.
insert("LJ", strokeJoin.get());
- /* TODO(vandebo) Font.
- if (fPaint.getTypeFace() != NULL) {
- SkRefPtr<SkPDFTypeFace> typeFace =
- SkPDFTypeFace::getFontForTypeFace(fPaint.getTypeFace);
- SkRefPtr<SkPDFObjRef> typeFaceRef = new SkPDFObjRef(typeFace.get());
- fontRef->unref(); // SkRefPtr and new both took a reference.
- SkRefPtr<SkPDFScalar> fontSize =
- new SkPDFScalar(fPaint.getTetSize());
- fontSize->unref(); // SkRefPtr and new both took a reference.
- SkRefPtr<SkPDFArray> font = new SkPDFArray();
- font->unref(); // SkRefPtr and new both took a reference.
- font->reserve(2);
- font->append(typeFaceRef.get());
- font->append(fontSize.get());
- insert("LJ", font.get());
- }
- */
-
SkRefPtr<SkPDFScalar> strokeWidth =
new SkPDFScalar(fPaint.getStrokeWidth());
strokeWidth->unref(); // SkRefPtr and new both took a reference.
@@ -150,14 +131,9 @@ bool SkPDFGraphicState::GSCanonicalEntry::operator==(
const SkPaint* b = gs.fPaint;
SkASSERT(a != NULL);
SkASSERT(b != NULL);
- SkTypeface* aFace = a->getTypeface();
- SkTypeface* bFace = b->getTypeface();
return SkColorGetA(a->getColor()) == SkColorGetA(b->getColor()) &&
a->getStrokeCap() == b->getStrokeCap() &&
a->getStrokeJoin() == b->getStrokeJoin() &&
- a->getTextSize() == b->getTextSize() &&
a->getStrokeWidth() == b->getStrokeWidth() &&
- a->getStrokeMiter() == b->getStrokeMiter() &&
- (aFace == NULL) == (bFace == NULL) &&
- (aFace == NULL || aFace->uniqueID() == bFace->uniqueID());
+ a->getStrokeMiter() == b->getStrokeMiter();
}
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index 8bff735da4..9649f0baec 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -97,11 +97,15 @@ void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog,
}
SkPDFString::SkPDFString(const char value[])
- : fValue(formatString(SkString(value))) {
+ : fValue(formatString(value, sizeof(value))) {
}
SkPDFString::SkPDFString(const SkString& value)
- : fValue(formatString(value)) {
+ : fValue(formatString(value.c_str(), value.size())) {
+}
+
+SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars)
+ : fValue(formatString(value, len, wideChars)) {
}
SkPDFString::~SkPDFString() {}
@@ -119,14 +123,40 @@ size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) {
return fValue.size();
}
-SkString SkPDFString::formatString(const SkString& input) {
- SkASSERT(input.size() <= kMaxLen);
+// static
+SkString SkPDFString::formatString(const char* input, size_t len) {
+ return doFormatString(input, len, false, false);
+}
+
+SkString SkPDFString::formatString(const uint16_t* input, size_t len,
+ bool wideChars) {
+ return doFormatString(input, len, true, wideChars);
+}
+
+// static
+SkString SkPDFString::doFormatString(const void* input, size_t len,
+ bool wideInput, bool wideOutput) {
+ SkASSERT(len <= kMaxLen);
+ const uint16_t* win = (const uint16_t*) input;
+ const char* cin = (const char*) input;
+
+ if (wideOutput) {
+ SkASSERT(wideInput);
+ SkString result;
+ result.append("<");
+ for (size_t i = 0; i < len; i++)
+ result.appendHex(win[i], 4);
+ result.append(">");
+ return result;
+ }
// 7-bit clean is a heuristic to decide what string format to use;
// a 7-bit clean string should require little escaping.
bool sevenBitClean = true;
- for (size_t i = 0; i < input.size(); i++) {
- if (input[i] & 0x80 || input[i] < ' ') {
+ for (size_t i = 0; i < len; i++) {
+ SkASSERT(!wideInput || !(win[i] & ~0xFF));
+ char val = wideInput ? win[i] : cin[i];
+ if (val & 0x80 || val < ' ') {
sevenBitClean = false;
break;
}
@@ -135,16 +165,21 @@ SkString SkPDFString::formatString(const SkString& input) {
SkString result;
if (sevenBitClean) {
result.append("(");
- for (size_t i = 0; i < input.size(); i++) {
- if (input[i] == '\\' || input[i] == '(' || input[i] == ')')
+ for (size_t i = 0; i < len; i++) {
+ SkASSERT(!wideInput || !(win[i] & ~0xFF));
+ char val = wideInput ? win[i] : cin[i];
+ if (val == '\\' || val == '(' || val == ')')
result.append("\\");
- result.append(input.c_str() + i, 1);
+ result.append(&val, 1);
}
result.append(")");
} else {
result.append("<");
- for (size_t i = 0; i < input.size(); i++)
- result.appendHex(input[i], 2);
+ for (size_t i = 0; i < len; i++) {
+ SkASSERT(!wideInput || !(win[i] & ~0xFF));
+ char val = wideInput ? win[i] : cin[i];
+ result.appendHex(val, 2);
+ }
result.append(">");
}
diff --git a/src/pdf/pdf_files.mk b/src/pdf/pdf_files.mk
index 86b3e0dd3b..8d721eb816 100644
--- a/src/pdf/pdf_files.mk
+++ b/src/pdf/pdf_files.mk
@@ -2,6 +2,7 @@ SOURCE := \
SkPDFCatalog.cpp \
SkPDFDevice.cpp \
SkPDFDocument.cpp \
+ SkPDFFont.cpp \
SkPDFFormXObject.cpp \
SkPDFGraphicState.cpp \
SkPDFImage.cpp \
diff --git a/src/ports/SkThread_win.cpp b/src/ports/SkThread_win.cpp
index d3f3e214be..cb3aa37dfd 100644
--- a/src/ports/SkThread_win.cpp
+++ b/src/ports/SkThread_win.cpp
@@ -18,17 +18,6 @@
#include <windows.h>
#include "SkThread.h"
-namespace {
-
-template <bool>
-struct CompileAssert {
-};
-
-} // namespace
-
-#define COMPILE_ASSERT(expr, msg) \
- typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
-
int32_t sk_atomic_inc(int32_t* addr)
{
// InterlockedIncrement returns the new value, we want to return the old.
@@ -42,8 +31,8 @@ int32_t sk_atomic_dec(int32_t* addr)
SkMutex::SkMutex(bool /* isGlobal */)
{
- COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),
- NotEnoughSizeForCriticalSection);
+ SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION),
+ NotEnoughSizeForCriticalSection);
InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage));
}