paint);
}
+// Create a PDF string. Maximum length (in bytes) is 65,535.
+// @param input A string value.
+// @param len The length of the input array.
+// @param wideChars True iff the upper byte in each uint16_t is
+// significant and should be encoded and not
+// discarded. If true, the upper byte is encoded
+// first. Otherwise, we assert the upper byte is
+// zero.
+static SkString format_wide_string(const uint16_t* input,
+ size_t len,
+ bool wideChars) {
+ if (wideChars) {
+ SkASSERT(2 * len < 65535);
+ static const char gHex[] = "0123456789ABCDEF";
+ SkString result(4 * len + 2);
+ result[0] = '<';
+ for (size_t i = 0; i < len; i++) {
+ result[4 * i + 1] = gHex[(input[i] >> 12) & 0xF];
+ result[4 * i + 2] = gHex[(input[i] >> 8) & 0xF];
+ result[4 * i + 3] = gHex[(input[i] >> 4) & 0xF];
+ result[4 * i + 4] = gHex[(input[i] ) & 0xF];
+ }
+ result[4 * len + 1] = '>';
+ return result;
+ } else {
+ SkASSERT(len <= 65535);
+ SkString tmp(len);
+ for (size_t i = 0; i < len; i++) {
+ SkASSERT(0 == input[i] >> 8);
+ tmp[i] = static_cast<uint8_t>(input[i]);
+ }
+ return SkPDFString::FormatString(tmp.c_str(), tmp.size());
+ }
+}
+
void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len,
SkScalar x, SkScalar y, const SkPaint& paint) {
NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false);
font, glyphIDsCopy.begin() + consumedGlyphCount,
availableGlyphs);
SkString encodedString =
- SkPDFString::FormatString(glyphIDsCopy.begin() + consumedGlyphCount,
- availableGlyphs, font->multiByteGlyphs());
+ format_wide_string(glyphIDsCopy.begin() + consumedGlyphCount,
+ availableGlyphs, font->multiByteGlyphs());
content.entry()->fContent.writeText(encodedString.c_str());
consumedGlyphCount += availableGlyphs;
content.entry()->fContent.writeText(" Tj\n");
align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y);
set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fContent);
SkString encodedString =
- SkPDFString::FormatString(&encodedValue, 1, font->multiByteGlyphs());
+ format_wide_string(&encodedValue, 1, font->multiByteGlyphs());
content.entry()->fContent.writeText(encodedString.c_str());
content.entry()->fContent.writeText(" Tj\n");
}
: 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() {}
void SkPDFString::emitObject(SkWStream* stream,
}
// 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) {
+SkString SkPDFString::FormatString(const char* cin, size_t len) {
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;
+ size_t characterCount = 2 + len;
for (size_t i = 0; i < len; i++) {
- SkASSERT(!wideInput || !(win[i] & ~0xFF));
- char val = wideInput ? win[i] : cin[i];
- if (val > '~' || val < ' ') {
+ if (cin[i] > '~' || cin[i] < ' ') {
sevenBitClean = false;
break;
}
+ if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
+ ++characterCount;
+ }
}
-
SkString result;
if (sevenBitClean) {
- result.append("(");
+ result.resize(characterCount);
+ char* str = result.writable_str();
+ *str++ = '(';
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("\\");
+ if (cin[i] == '\\' || cin[i] == '(' || cin[i] == ')') {
+ *str++ = '\\';
}
- result.append(&val, 1);
+ *str++ = cin[i];
}
- result.append(")");
+ *str++ = ')';
} else {
- result.append("<");
+ result.resize(2 * len + 2);
+ char* str = result.writable_str();
+ *str++ = '<';
for (size_t i = 0; i < len; i++) {
- SkASSERT(!wideInput || !(win[i] & ~0xFF));
- unsigned char val = wideInput ? win[i] : cin[i];
- result.appendHex(val, 2);
+ uint8_t c = static_cast<uint8_t>(cin[i]);
+ static const char gHex[] = "0123456789ABCDEF";
+ *str++ = gHex[(c >> 4) & 0xF];
+ *str++ = gHex[(c ) & 0xF];
}
- result.append(">");
+ *str++ = '>';
}
-
return result;
}
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.
const SkPDFSubstituteMap& substitutes) override;
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;
- static SkString DoFormatString(const void* input, size_t len,
- bool wideInput, bool wideOutput);
-
typedef SkPDFObject INHERITED;
};