aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Bryce Thomas <bryct@amazon.com>2018-03-02 13:54:21 -0800
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-02 22:20:19 +0000
commit95a7b76a44edd2f25423a4d395df553b80fe06d7 (patch)
tree6a5e66c6b2026e985248f092d928b39c19f677e1
parent419abf335af36cc9928019bbd9c075944ae59a0a (diff)
dm: support printing specific page of mskp to SVG
Currently with dm, it's possible to convert an .mskp to a multi-page PDF as follows: out/Release/dm --src mskp --mskps /tmp/filename.mskp -w /tmp \ --config pdf --verbose The SVG equivalent partially works, although only outputs the first page: out/Release/dm --src mskp --mskps /tmp/filename.mskp -w /tmp \ --config svg --verbose This CL adds support for passing extended options to SVG. Specifically, the 'page' option , which now determines which page of the source mskp gets converted to the SVG output. The new syntax is as follows: out/Release/dm --src mskp --mskps /tmp/filename.mskp -w /tmp \ --config svg[page=2] --verbose The `[key=value]` syntax is the same extended options syntax currently used by dm with --config gpu, e.g. `gpu[api=gl,color=8888]`. BUG=skia:7601 Change-Id: I3523d79b1cdbbba9e80fd46501331877091bdead Reviewed-on: https://skia-review.googlesource.com/105404 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Mike Klein <mtklein@chromium.org>
-rw-r--r--dm/DM.cpp4
-rw-r--r--dm/DMSrcSink.cpp15
-rw-r--r--dm/DMSrcSink.h5
-rw-r--r--tools/flags/SkCommonFlagsConfig.cpp235
-rw-r--r--tools/flags/SkCommonFlagsConfig.h16
5 files changed, 191 insertions, 84 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 1d3d815647..972c70d484 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -899,6 +899,10 @@ static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLi
}
}
#endif
+ if (const SkCommandLineConfigSvg* svgConfig = config->asConfigSvg()) {
+ int pageIndex = svgConfig->getPageIndex();
+ return new SVGSink(pageIndex);
+ }
#define SINK(t, sink, ...) if (config->getBackend().equals(t)) { return new sink(__VA_ARGS__); }
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 2229b9c26d..149138d832 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -1838,14 +1838,23 @@ Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) cons
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-SVGSink::SVGSink() {}
+SVGSink::SVGSink(int pageIndex) : fPageIndex(pageIndex) {}
Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const {
#if defined(SK_XML)
+ if (src.pageCount() > 1) {
+ int pageCount = src.pageCount();
+ if (fPageIndex > pageCount - 1) {
+ return Error(SkStringPrintf("Page index %d too high for document with only %d pages.",
+ fPageIndex, pageCount));
+ }
+ }
std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst));
- return src.draw(SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
+ return src.draw(fPageIndex,
+ SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()),
SkIntToScalar(src.size().height())),
- xmlWriter.get()).get());
+ xmlWriter.get())
+ .get());
#else
return Error("SVG sink is disabled.");
#endif // SK_XML
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 6cc5df690f..227ef5341a 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -458,11 +458,14 @@ public:
class SVGSink : public Sink {
public:
- SVGSink();
+ SVGSink(int pageIndex = 0);
Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
const char* fileExtension() const override { return "svg"; }
SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
+
+private:
+ int fPageIndex;
};
diff --git a/tools/flags/SkCommonFlagsConfig.cpp b/tools/flags/SkCommonFlagsConfig.cpp
index 7ff6ce6849..85495c68d8 100644
--- a/tools/flags/SkCommonFlagsConfig.cpp
+++ b/tools/flags/SkCommonFlagsConfig.cpp
@@ -7,6 +7,7 @@
#include "SkCommonFlagsConfig.h"
#include "SkImageInfo.h"
+#include "SkTHash.h"
#include <stdlib.h>
@@ -187,42 +188,6 @@ SkCommandLineConfig::SkCommandLineConfig(const SkString& tag, const SkString& ba
SkCommandLineConfig::~SkCommandLineConfig() {
}
-#if SK_SUPPORT_GPU
-SkCommandLineConfigGpu::SkCommandLineConfigGpu(
- const SkString& tag, const SkTArray<SkString>& viaParts, ContextType contextType, bool useNVPR,
- bool useDIText, int samples, SkColorType colorType, SkAlphaType alphaType,
- sk_sp<SkColorSpace> colorSpace, bool useStencilBuffers, bool testThreading)
- : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
- , fContextType(contextType)
- , fContextOverrides(ContextOverrides::kNone)
- , fUseDIText(useDIText)
- , fSamples(samples)
- , fColorType(colorType)
- , fAlphaType(alphaType)
- , fColorSpace(std::move(colorSpace))
- , fTestThreading(testThreading) {
- if (useNVPR) {
- fContextOverrides |= ContextOverrides::kRequireNVPRSupport;
- } else {
- // We don't disable NVPR for instanced configs. Otherwise the caps wouldn't use mixed
- // samples and we couldn't test the mixed samples backend for simple shapes.
- fContextOverrides |= ContextOverrides::kDisableNVPR;
- }
- // Subtle logic: If the config has a color space attached, we're going to be rendering to sRGB,
- // so we need that capability. In addition, to get the widest test coverage, we DO NOT require
- // that we can disable sRGB decode. (That's for rendering sRGB sources to legacy surfaces).
- //
- // If the config doesn't have a color space attached, we're going to be rendering in legacy
- // mode. In that case, we don't require sRGB capability and we defer to the client to decide on
- // sRGB decode control.
- if (fColorSpace) {
- fContextOverrides |= ContextOverrides::kRequireSRGBSupport;
- fContextOverrides |= ContextOverrides::kAllowSRGBWithoutDecodeControl;
- }
- if (!useStencilBuffers) {
- fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
- }
-}
static bool parse_option_int(const SkString& value, int* outInt) {
if (value.isEmpty()) {
return false;
@@ -246,6 +211,7 @@ static bool parse_option_bool(const SkString& value, bool* outBool) {
}
return false;
}
+#if SK_SUPPORT_GPU
static bool parse_option_gpu_api(const SkString& value,
SkCommandLineConfigGpu::ContextType* outContextType) {
if (value.equals("gl")) {
@@ -385,74 +351,180 @@ static bool parse_option_gpu_color(const SkString& value,
}
return false;
}
+#endif
+
+// Extended options take form --config item[key1=value1,key2=value2,...]
+// Example: --config gpu[api=gl,color=8888]
+class ExtendedOptions {
+public:
+ ExtendedOptions(const SkString& optionsString, bool* outParseSucceeded) {
+ SkTArray<SkString> optionParts;
+ SkStrSplit(optionsString.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
+ for (int i = 0; i < optionParts.count(); ++i) {
+ SkTArray<SkString> keyValueParts;
+ SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
+ if (keyValueParts.count() != 2) {
+ *outParseSucceeded = false;
+ return;
+ }
+ const SkString& key = keyValueParts[0];
+ const SkString& value = keyValueParts[1];
+ if (fOptionsMap.find(key) == nullptr) {
+ fOptionsMap.set(key, value);
+ } else {
+ // Duplicate values are not allowed.
+ *outParseSucceeded = false;
+ return;
+ }
+ }
+ *outParseSucceeded = true;
+ }
+
+#if SK_SUPPORT_GPU
+ bool get_option_gpu_color(const char* optionKey,
+ SkColorType* outColorType,
+ SkAlphaType* alphaType,
+ sk_sp<SkColorSpace>* outColorSpace,
+ bool optional = true) const {
+ SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+ if (optionValue == nullptr) {
+ return optional;
+ }
+ return parse_option_gpu_color(*optionValue, outColorType, alphaType, outColorSpace);
+ }
+
+ bool get_option_gpu_api(const char* optionKey,
+ SkCommandLineConfigGpu::ContextType* outContextType,
+ bool optional = true) const {
+ SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+ if (optionValue == nullptr) {
+ return optional;
+ }
+ return parse_option_gpu_api(*optionValue, outContextType);
+ }
+#endif
+
+ bool get_option_int(const char* optionKey, int* outInt, bool optional = true) const {
+ SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+ if (optionValue == nullptr) {
+ return optional;
+ }
+ return parse_option_int(*optionValue, outInt);
+ }
+
+ bool get_option_bool(const char* optionKey, bool* outBool, bool optional = true) const {
+ SkString* optionValue = fOptionsMap.find(SkString(optionKey));
+ if (optionValue == nullptr) {
+ return optional;
+ }
+ return parse_option_bool(*optionValue, outBool);
+ }
+
+private:
+ SkTHashMap<SkString, SkString> fOptionsMap;
+};
+
+#if SK_SUPPORT_GPU
+SkCommandLineConfigGpu::SkCommandLineConfigGpu(
+ const SkString& tag, const SkTArray<SkString>& viaParts, ContextType contextType, bool useNVPR,
+ bool useDIText, int samples, SkColorType colorType, SkAlphaType alphaType,
+ sk_sp<SkColorSpace> colorSpace, bool useStencilBuffers, bool testThreading)
+ : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
+ , fContextType(contextType)
+ , fContextOverrides(ContextOverrides::kNone)
+ , fUseDIText(useDIText)
+ , fSamples(samples)
+ , fColorType(colorType)
+ , fAlphaType(alphaType)
+ , fColorSpace(std::move(colorSpace))
+ , fTestThreading(testThreading) {
+ if (useNVPR) {
+ fContextOverrides |= ContextOverrides::kRequireNVPRSupport;
+ } else {
+ // We don't disable NVPR for instanced configs. Otherwise the caps wouldn't use mixed
+ // samples and we couldn't test the mixed samples backend for simple shapes.
+ fContextOverrides |= ContextOverrides::kDisableNVPR;
+ }
+ // Subtle logic: If the config has a color space attached, we're going to be rendering to sRGB,
+ // so we need that capability. In addition, to get the widest test coverage, we DO NOT require
+ // that we can disable sRGB decode. (That's for rendering sRGB sources to legacy surfaces).
+ //
+ // If the config doesn't have a color space attached, we're going to be rendering in legacy
+ // mode. In that case, we don't require sRGB capability and we defer to the client to decide on
+ // sRGB decode control.
+ if (fColorSpace) {
+ fContextOverrides |= ContextOverrides::kRequireSRGBSupport;
+ fContextOverrides |= ContextOverrides::kAllowSRGBWithoutDecodeControl;
+ }
+ if (!useStencilBuffers) {
+ fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
+ }
+}
SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
const SkTArray<SkString>& vias,
const SkString& options) {
// Defaults for GPU backend.
- bool seenAPI = false;
SkCommandLineConfigGpu::ContextType contextType = GrContextFactory::kGL_ContextType;
- bool seenUseNVPR = false;
bool useNVPR = false;
- bool seenUseDIText =false;
bool useDIText = false;
- bool seenSamples = false;
int samples = 1;
- bool seenColor = false;
SkColorType colorType = kRGBA_8888_SkColorType;
SkAlphaType alphaType = kPremul_SkAlphaType;
sk_sp<SkColorSpace> colorSpace = nullptr;
- bool seenUseStencils = false;
bool useStencils = true;
- bool seenTestThreading = false;
bool testThreading = false;
- SkTArray<SkString> optionParts;
- SkStrSplit(options.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
- for (int i = 0; i < optionParts.count(); ++i) {
- SkTArray<SkString> keyValueParts;
- SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
- if (keyValueParts.count() != 2) {
- return nullptr;
- }
- const SkString& key = keyValueParts[0];
- const SkString& value = keyValueParts[1];
- bool valueOk = false;
- if (key.equals("api") && !seenAPI) {
- valueOk = parse_option_gpu_api(value, &contextType);
- seenAPI = true;
- } else if (key.equals("nvpr") && !seenUseNVPR) {
- valueOk = parse_option_bool(value, &useNVPR);
- seenUseNVPR = true;
- } else if (key.equals("dit") && !seenUseDIText) {
- valueOk = parse_option_bool(value, &useDIText);
- seenUseDIText = true;
- } else if (key.equals("samples") && !seenSamples) {
- valueOk = parse_option_int(value, &samples);
- seenSamples = true;
- } else if (key.equals("color") && !seenColor) {
- valueOk = parse_option_gpu_color(value, &colorType, &alphaType, &colorSpace);
- seenColor = true;
- } else if (key.equals("stencils") && !seenUseStencils) {
- valueOk = parse_option_bool(value, &useStencils);
- seenUseStencils = true;
- } else if (key.equals("testThreading") && !seenTestThreading) {
- valueOk = parse_option_bool(value, &testThreading);
- seenTestThreading = true;
- }
- if (!valueOk) {
- return nullptr;
- }
+ bool parseSucceeded = false;
+ ExtendedOptions extendedOptions(options, &parseSucceeded);
+ if (!parseSucceeded) {
+ return nullptr;
}
- if (!seenAPI) {
+
+ bool validOptions =
+ extendedOptions.get_option_gpu_api("api", &contextType, false) &&
+ extendedOptions.get_option_bool("nvpr", &useNVPR) &&
+ extendedOptions.get_option_bool("dit", &useDIText) &&
+ extendedOptions.get_option_int("samples", &samples) &&
+ extendedOptions.get_option_gpu_color("color", &colorType, &alphaType, &colorSpace) &&
+ extendedOptions.get_option_bool("stencils", &useStencils) &&
+ extendedOptions.get_option_bool("testThreading", &testThreading);
+
+ if (!validOptions) {
return nullptr;
}
+
return new SkCommandLineConfigGpu(tag, vias, contextType, useNVPR, useDIText,
samples, colorType, alphaType, colorSpace, useStencils,
testThreading);
}
#endif
+SkCommandLineConfigSvg::SkCommandLineConfigSvg(const SkString& tag,
+ const SkTArray<SkString>& viaParts, int pageIndex)
+ : SkCommandLineConfig(tag, SkString("svg"), viaParts), fPageIndex(pageIndex) {}
+
+SkCommandLineConfigSvg* parse_command_line_config_svg(const SkString& tag,
+ const SkTArray<SkString>& vias,
+ const SkString& options) {
+ // Defaults for SVG backend.
+ int pageIndex = 0;
+
+ bool parseSucceeded = false;
+ ExtendedOptions extendedOptions(options, &parseSucceeded);
+ if (!parseSucceeded) {
+ return nullptr;
+ }
+
+ bool validOptions = extendedOptions.get_option_int("page", &pageIndex);
+
+ if (!validOptions) {
+ return nullptr;
+ }
+
+ return new SkCommandLineConfigSvg(tag, vias, pageIndex);
+}
+
void ParseConfigs(const SkCommandLineFlags::StringArray& configs,
SkCommandLineConfigArray* outResult) {
outResult->reset();
@@ -502,6 +574,9 @@ void ParseConfigs(const SkCommandLineFlags::StringArray& configs,
parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions);
}
#endif
+ if (extendedBackend.equals("svg")) {
+ parsedConfig = parse_command_line_config_svg(tag, vias, extendedOptions);
+ }
if (!parsedConfig) {
parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias);
}
diff --git a/tools/flags/SkCommonFlagsConfig.h b/tools/flags/SkCommonFlagsConfig.h
index 49d536c0cd..d88edf1c3b 100644
--- a/tools/flags/SkCommonFlagsConfig.h
+++ b/tools/flags/SkCommonFlagsConfig.h
@@ -19,6 +19,7 @@ DECLARE_string(config);
#if SK_SUPPORT_GPU
class SkCommandLineConfigGpu;
#endif
+class SkCommandLineConfigSvg;
// SkCommandLineConfig represents a Skia rendering configuration string.
// The string has following form:
@@ -34,6 +35,7 @@ class SkCommandLineConfig {
#if SK_SUPPORT_GPU
virtual const SkCommandLineConfigGpu* asConfigGpu() const { return nullptr; }
#endif
+ virtual const SkCommandLineConfigSvg* asConfigSvg() const { return nullptr; }
const SkString& getTag() const { return fTag; }
const SkString& getBackend() const { return fBackend; }
const SkTArray<SkString>& getViaParts() const { return fViaParts; }
@@ -85,6 +87,20 @@ class SkCommandLineConfigGpu : public SkCommandLineConfig {
};
#endif
+// SkCommandLineConfigSvg is a SkCommandLineConfig that extracts information out of the backend
+// part of the tag. It is constructed tags that have:
+// * backends of form "svg[option=value,option2=value,...]"
+class SkCommandLineConfigSvg : public SkCommandLineConfig {
+public:
+ SkCommandLineConfigSvg(const SkString& tag, const SkTArray<SkString>& viaParts, int pageIndex);
+ const SkCommandLineConfigSvg* asConfigSvg() const override { return this; }
+
+ int getPageIndex() const { return fPageIndex; }
+
+private:
+ int fPageIndex;
+};
+
typedef SkTArray<std::unique_ptr<SkCommandLineConfig>, true> SkCommandLineConfigArray;
void ParseConfigs(const SkCommandLineFlags::StringArray& configList,
SkCommandLineConfigArray* outResult);