--- /dev/null
+ /*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+ #include "SkTypes.h"
+ #if defined(SK_BUILD_FOR_WIN32)
+
+ #include "SkXPSDocument.h"
+ #include "SkStream.h"
+ #include "SkHRESULT.h"
+
+ SkXPSDocument::SkXPSDocument(SkWStream* stream,
+ SkScalar dpi,
+ SkTScopedComPtr<IXpsOMObjectFactory> xpsFactory)
+ : SkDocument(stream, nullptr)
+ , fXpsFactory(std::move(xpsFactory))
+ , fDevice(SkISize{10000, 10000})
+ {
+ const SkScalar kPointsPerMeter = SkDoubleToScalar(360000.0 / 127.0);
+ fUnitsPerMeter.set(kPointsPerMeter, kPointsPerMeter);
+ SkScalar pixelsPerMeterScale = SkDoubleToScalar(dpi * 5000.0 / 127.0);
+ fPixelsPerMeter.set(pixelsPerMeterScale, pixelsPerMeterScale);
+ SkASSERT(fXpsFactory);
+ fDevice.beginPortfolio(stream, fXpsFactory.get());
+ }
+
+ SkXPSDocument::~SkXPSDocument() {
+ // subclasses must call close() in their destructors
+ this->close();
+ }
+
+ SkCanvas* SkXPSDocument::onBeginPage(SkScalar width,
+ SkScalar height,
+ const SkRect& trimBox) {
+ fDevice.beginSheet(fUnitsPerMeter, fPixelsPerMeter,
+ SkSize::Make(width, height));
+ fCanvas.reset(new SkCanvas(&fDevice));
+ fCanvas->clipRect(trimBox);
+ fCanvas->translate(trimBox.x(), trimBox.y());
+ return fCanvas.get();
+ }
+
+ void SkXPSDocument::onEndPage() {
+ SkASSERT(fCanvas.get());
+ fCanvas->flush();
+ fCanvas.reset(nullptr);
+ fDevice.endSheet();
+ }
+
+ void SkXPSDocument::onClose(SkWStream*) {
+ SkASSERT(!fCanvas.get());
+ (void)fDevice.endPortfolio();
+ }
+
+ void SkXPSDocument::onAbort() {}
+
+ ///////////////////////////////////////////////////////////////////////////////
+
++// UWP Mobile does not support XPS, but Desktop does
++static inline bool xps_available() {
++#ifdef SK_BUILD_FOR_WINRT
++ static bool available = []{
++ SkTScopedComPtr<IXpsOMObjectFactory> factory;
++ auto hr = CoCreateInstance(
++ CLSID_XpsOMObjectFactory,
++ nullptr,
++ CLSCTX_INPROC_SERVER,
++ IID_PPV_ARGS(&factory));
++ return SUCCEEDED(hr);
++ }();
++ return available;
++#else
++ return true;
++#endif
++}
++
+ sk_sp<SkDocument> SkDocument::MakeXPS(SkWStream* stream,
+ IXpsOMObjectFactory* factoryPtr,
+ SkScalar dpi) {
++ if (!xps_available()) {
++ return nullptr;
++ }
+ SkTScopedComPtr<IXpsOMObjectFactory> factory(SkSafeRefComPtr(factoryPtr));
+ return stream && factory
+ ? sk_make_sp<SkXPSDocument>(stream, dpi, std::move(factory))
+ : nullptr;
+ }
+
+ #endif//defined(SK_BUILD_FOR_WIN32)
REPORTER_ASSERT(r, nonEmpty);
REPORTER_ASSERT(r, region.isComplex());
test_write(region, r);
+
+ SkRegion complexRegion;
+ Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 1, 1));
+ Union(&complexRegion, SkIRect::MakeXYWH(0, 0, 3, 3));
+ Union(&complexRegion, SkIRect::MakeXYWH(10, 0, 3, 3));
+ Union(&complexRegion, SkIRect::MakeXYWH(0, 10, 13, 3));
+ test_write(complexRegion, r);
+
+ Union(&complexRegion, SkIRect::MakeXYWH(10, 20, 3, 3));
+ Union(&complexRegion, SkIRect::MakeXYWH(0, 20, 3, 3));
+ test_write(complexRegion, r);
+ }
+
+ DEF_TEST(Region_readFromMemory_bad, r) {
+ // These assume what our binary format is: conceivably we could change it
+ // and might need to remove or change some of these tests.
+ SkRegion region;
+
+ {
+ // invalid boundary rectangle
+ int32_t data[5] = {0, 4, 4, 8, 2};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ // Region Layout, Serialized Format:
+ // COUNT LEFT TOP RIGHT BOTTOM Y_SPAN_COUNT TOTAL_INTERVAL_COUNT
+ // Top ( Bottom Span_Interval_Count ( Left Right )* Sentinel )+ Sentinel
+ {
+ // Example of valid data
+ int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, 2147483647};
+ REPORTER_ASSERT(r, 0 != region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // Short count
+ int32_t data[] = {8, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, 2147483647};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // bounds don't match
+ int32_t data[] = {9, 0, 0, 10, 11, 1, 2, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, 2147483647};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // bad yspan count
+ int32_t data[] = {9, 0, 0, 10, 10, 2, 2, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, 2147483647};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // bad int count
+ int32_t data[] = {9, 0, 0, 10, 10, 1, 3, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, 2147483647};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // bad final sentinal
+ int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
+ 2147483647, -1};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
+ {
+ // bad row sentinal
+ int32_t data[] = {9, 0, 0, 10, 10, 1, 2, 0, 10, 2, 0, 4, 6, 10,
+ -1, 2147483647};
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data, sizeof(data)));
+ }
}
+
+DEF_TEST(Region_readFromMemory_bad, r) {
+ // These assume what our binary format is: conceivably we could change it
+ // and might need to remove or change some of these tests.
+ SkRegion region;
+
+ static const char data0[] =
+ "\2\0\0\0\277]\345\222\\\2G\252\0\177'\10\203\236\211>\377\340@\351"
+ "!\370y\3\31\232r\353\343\336Ja\177\377\377\377\244\301\362:Q\\\0\0"
+ "\1\200\263\214\374\276\336P\225^\230\20UH N\265\357\177\240\0\306\377"
+ "\177\346\222S \0\375\0\332\247 \302I\240H\374\200lk\r`\0375\324W\215"
+ "\270tE^,\224n\310fy\377\231AH\16\235A\371\315\347\360\265\372r\232"
+ "\301\216\35\227:\265]\32\20W\263yc\207\246\270tE^,\224n\310sy\2\0A"
+ "\14\241SQ\\\303\364\0\0\1\200\0\0\374k\r`\0375\324Wp\270\267\313\313"
+ "\313\313\313@\277\365b\341\343\336Ja\357~\263\0\2\333\260\220\\\303"
+ "\364\265\332\267\242\325nlX\367\27I4444;\266\256\37/M\207";
+ size_t data0length = 221;
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data0, data0length));
+
+ static const char data1[] =
+ "\2\0\0\0\\\2G\252\0\177'\10\247 \302I\240H\374\200lk\r`\0375\324Wr"
+ "\232\301\216\35\227:\265]\32\20W\263yc\207\246\270tE^,\224n\310sy\2"
+ "\0A\14\241SQ\\\303\364\0\0\1\200\0\0\374k\r`\0375\324Wp\270\267\313"
+ "\313\313\313\313@\277\365b\341\343\336Ja\357~\263\0\2\333\260\220\\"
+ "\303\364\265\332\267\242\325nlX\367\27I4444;\266\256\37/M\207";
+ size_t data1length = 129;
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data1, data1length));
+
+ static const char data2[] =
+ " \0\0\0`\6\363\234AH\26\235\0\0\0\0\251\217\27I\27C\361,\320u\3171"
+ "\10.\206\277]\345\222\334\2C\252\242a'\10\251\31\326\372\334A\277\30"
+ "\240M\275v\201\271\3527\215{)S\3771{\345Z\250\23\213\331\23j@\13\220"
+ "\200Z^-\20\212=;\355\314\36\260c\224M\16\271Szy\373\204M\21\177\251"
+ "\275\r\274M\370\201\243^@\343\236JaS\204\3212\244\301\327\22\352KI"
+ "\207\350z\300\250\372\26\14\2\233K\330\16\251\230\223\r\"\243\271\17"
+ ")\260\262\2[a.*.4\14\344\307\350\3\0\0-\350G!\31\300\205\205\205\205"
+ "\205\205\205\205\205\205\205\205\205\205\205\205\305m\311<Q\347\30"
+ "\324\203f\2614\3115\206\214@:\346n\254\37\225\263\214\374\276\336\23"
+ "\270\304\262\25\24_\342\223\253\351L\30\372\373\243\240g\0367V\336"
+ "P\7-1{\345Z\250\23\213P\225^\230\27UH\206N\265\357\177\262\302\306"
+ "kk\7\233\234N\32@\355H\327\34\337\0V\30 \225\35\225\233\253\0144>\310"
+ "\352\346L\232\215\270t[^,\224l\312f\2025?}\1ZL\217wf8C\346\222S\240"
+ "\203\375\374\332\247 \302I\271H\0\0lk\22`\0375\324W\374\265\342\243"
+ "yL\211\215\270tE^,\224l\312f\2025?}\1ZL\217wf8C\333\370_.\277A\277"
+ "^\\\313!\342\340\213\210\244\272\33\275\360\301\347\315\377\6a\272"
+ "kyi:W\332\366\5\312F\217c\243\20,\"\240\347o\375\277\317}HEji\367\374"
+ "\331\214\314\242x\356\340\350\362r$\222\266\325\201\234\267P\243N\361"
+ "++++++++\370+@++\205!8B\255L\3\3416\335$\\\r\265W[F\326\316w{.\306"
+ ">f2i\244\242=Y\236\364\302\357xR:Q\\\303\364\265\332\200\242\325nl"
+ "X\373\307\5<-";
+ size_t data2length = 512;
+ REPORTER_ASSERT(r, 0 == region.readFromMemory(data2, data2length));
+}