diff options
author | Tom Sepez <tsepez@chromium.org> | 2018-10-23 21:38:28 +0000 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2018-10-23 21:38:28 +0000 |
commit | 5ff1ddeb54a425e1af25607646697e93a39bd51d (patch) | |
tree | 31266c1e22ab146883cc165bc7925a341ce28a9d | |
parent | 401077e47c49c3b1cb865ee6f1f29a931a6ca45b (diff) | |
download | pdfium-5ff1ddeb54a425e1af25607646697e93a39bd51d.tar.xz |
Test color.convert() and equal() from JS (and fix comparison logic).
Currently, color.equal(a, b) may not give the same result as
color.equal(b, a) since arg1 is converted to be the type of
arg2, and some of these conversions lose information. Instead
promote to the type with the most components in the hope of
preserving the most information.
Better error message when there are the right number of parameters
but the types are wrong.
Change-Id: I1d93fa29db4fb65e0f7c07c3ba7d9ca87ebf7bc9
Reviewed-on: https://pdfium-review.googlesource.com/c/44413
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
-rw-r--r-- | core/fxge/cfx_color.cpp | 9 | ||||
-rw-r--r-- | core/fxge/cfx_color.h | 1 | ||||
-rw-r--r-- | fxjs/cjs_color.cpp | 20 | ||||
-rw-r--r-- | testing/resources/javascript/color_methods.in | 133 | ||||
-rw-r--r-- | testing/resources/javascript/color_methods_expected.txt | 57 |
5 files changed, 214 insertions, 6 deletions
diff --git a/core/fxge/cfx_color.cpp b/core/fxge/cfx_color.cpp index e4d89dc2ff..a19f040e51 100644 --- a/core/fxge/cfx_color.cpp +++ b/core/fxge/cfx_color.cpp @@ -11,6 +11,15 @@ #include "core/fpdfapi/parser/cpdf_array.h" #include "core/fpdfdoc/cpdf_defaultappearance.h" +// Color types are orded by increasing number of components so we can +// choose a best color type during some conversions. +static_assert(CFX_Color::kTransparent < CFX_Color::kGray, + "color type values must be ordered"); +static_assert(CFX_Color::kGray < CFX_Color::kRGB, + "color type values must be ordered"); +static_assert(CFX_Color::kRGB < CFX_Color::kCMYK, + "color type values must be ordered"); + namespace { bool InRange(float comp) { diff --git a/core/fxge/cfx_color.h b/core/fxge/cfx_color.h index d6fabad989..1dd512a42d 100644 --- a/core/fxge/cfx_color.h +++ b/core/fxge/cfx_color.h @@ -14,6 +14,7 @@ struct CFX_Color { static CFX_Color ParseColor(const CPDF_Array& array); static CFX_Color ParseColor(const ByteString& str); + // Ordered by increasing number of components. enum Type { kTransparent = 0, kGray, kRGB, kCMYK }; explicit CFX_Color(FX_COLORREF ref) diff --git a/fxjs/cjs_color.cpp b/fxjs/cjs_color.cpp index 7ce5c2937c..0d4065eb6a 100644 --- a/fxjs/cjs_color.cpp +++ b/fxjs/cjs_color.cpp @@ -6,6 +6,7 @@ #include "fxjs/cjs_color.h" +#include <algorithm> #include <vector> #include "core/fxge/cfx_color.h" @@ -271,10 +272,12 @@ CJS_Result CJS_Color::SetPropertyHelper(CJS_Runtime* pRuntime, CJS_Result CJS_Color::convert(CJS_Runtime* pRuntime, const std::vector<v8::Local<v8::Value>>& params) { - int iSize = params.size(); - if (iSize < 2 || params[0].IsEmpty() || !params[0]->IsArray()) + if (params.size() < 2) return CJS_Result::Failure(JSMessage::kParamError); + if (params[0].IsEmpty() || !params[0]->IsArray()) + return CJS_Result::Failure(JSMessage::kTypeError); + WideString sDestSpace = pRuntime->ToWideString(params[1]); int nColorType = CFX_Color::kTransparent; if (sDestSpace == L"T") @@ -298,9 +301,12 @@ CJS_Result CJS_Color::convert(CJS_Runtime* pRuntime, CJS_Result CJS_Color::equal(CJS_Runtime* pRuntime, const std::vector<v8::Local<v8::Value>>& params) { - if (params.size() < 2 || params[0].IsEmpty() || !params[0]->IsArray() || - params[1].IsEmpty() || !params[1]->IsArray()) { + if (params.size() < 2) return CJS_Result::Failure(JSMessage::kParamError); + + if (params[0].IsEmpty() || !params[0]->IsArray() || params[1].IsEmpty() || + !params[1]->IsArray()) { + return CJS_Result::Failure(JSMessage::kTypeError); } CFX_Color color1 = @@ -308,6 +314,8 @@ CJS_Result CJS_Color::equal(CJS_Runtime* pRuntime, CFX_Color color2 = ConvertArrayToPWLColor(pRuntime, pRuntime->ToArray(params[1])); - color1 = color1.ConvertColorType(color2.nColorType); - return CJS_Result::Success(pRuntime->NewBoolean(color1 == color2)); + // Relies on higher values having more components. + int32_t best = std::max(color1.nColorType, color2.nColorType); + return CJS_Result::Success(pRuntime->NewBoolean( + color1.ConvertColorType(best) == color2.ConvertColorType(best))); } diff --git a/testing/resources/javascript/color_methods.in b/testing/resources/javascript/color_methods.in new file mode 100644 index 0000000000..1268657650 --- /dev/null +++ b/testing/resources/javascript/color_methods.in @@ -0,0 +1,133 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /Pages 2 0 R + /OpenAction 10 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [ + 3 0 R + ] +>> +endobj +% Page number 0. +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /MediaBox [0 0 612 792] +>> +endobj +% OpenAction action +{{object 10 0}} << + /Type /Action + /S /JavaScript + /JS 11 0 R +>> +endobj +% JS program to exexute +{{object 11 0}} << + {{streamlen}} +>> +stream +function expect(str, expected) { + try { + var result = eval(str); + if (result == expected) { + app.alert('PASS: ' + str + ' = ' + result); + } else { + app.alert('FAIL: ' + str + ' = ' + result + ', expected = ' + expected); + } + } catch (e) { + app.alert('ERROR: ' + e.toString()); + } +} + +function expectError(str) { + try { + var result = eval(str); + app.alert('FAIL: ' + str + ' = ' + result + ', expected to throw error'); + } catch (e) { + app.alert('PASS: ' + str + ' threw error ' + e.toString()); + } +} + +try { + expectError("color.convert()"); + expectError("color.convert(1)"); + expectError("color.convert(undefined, 'RGB')"); + expectError("color.convert('BOGUS', 'RGB')"); + expectError("color.convert('{}', 'RGB')"); + + // Can't convert transparent into anything else. + expect("color.convert(['T'], 'BOGUS')", "T"); + expect("color.convert(['T'], 'T')", "T"); + expect("color.convert(['T'], 'G')", "T"); + expect("color.convert(['T'], 'RGB')", "T"); + expect("color.convert(['T'], 'CMYK')", "T"); + + expect("color.convert(['G', 0.50], 'BOGUS')", "T"); + expect("color.convert(['G', 0.50], 'T')", "T"); + expect("color.convert(['G', 0.50], 'G')", "G,0.5"); + expect("color.convert(['G', 0.50], 'RGB')", "RGB,0.5,0.5,0.5"); + expect("color.convert(['G', 0.50], 'CMYK')", "CMYK,0,0,0,0.5"); + + expect("color.convert(['RGB', 0.25, 0.50, 0.75], 'BOGUS')", "T"); + expect("color.convert(['RGB', 0.25, 0.50, 0.75], 'T')", "T"); + expect("color.convert(['RGB', 1.00, 1.00, 1.00], 'G')", "G,1"); + expect("color.convert(['RGB', 0.25, 0.50, 0.75], 'RGB')", "RGB,0.25,0.5,0.75"); + expect("color.convert(['RGB', 0.25, 0.50, 0.75], 'CMYK')", "CMYK,0.75,0.5,0.25,0.25"); + + expect("color.convert(['CMYK',0.25,0.25,0.25,0.50], 'BOGUS')", "T"); + expect("color.convert(['CMYK',0.25,0.25,0.25,0.50], 'T')", "T"); + expect("color.convert(['CMYK',0.25,0.25,0.25,0.50], 'G')", "G,0.25"); + expect("color.convert(['CMYK',0.25,0.25,0.25,0.50], 'RGB')", "RGB,0.25,0.25,0.25"); + expect("color.convert(['CMYK',0.25,0.25,0.25,0.50], 'CMYK')", "CMYK,0.25,0.25,0.25,0.5"); + + expectError("color.equal()"); + expectError("color.equal(1)"); + expectError("color.equal(undefined, undefined)"); + expectError("color.equal(undefined, 'BOGUS')"); + expectError("color.equal('BOGUS', 'BOGUS')"); + expectError("color.equal('BOGUS', ['T'])"); + expectError("color.equal(['T'], 'BOGUS')"); + + expect("color.equal(['T'], ['T'])", true); + expect("color.equal(['T'], ['G', 0])", false); + expect("color.equal(['T'], ['RGB', 0, 0, 0])", false); + expect("color.equal(['T'], ['CMYK', 0, 0, 0, 0])", false); + + expect("color.equal(['G', 0.50], ['T'])", false); + expect("color.equal(['G', 0.50], ['G', 0])", false); + expect("color.equal(['G', 0.50], ['G', 0.50])", true); + expect("color.equal(['G', 0.50], ['RGB', 0, 0, 0])", false); + expect("color.equal(['G', 0.50], ['RGB', 0.50, 0.50, 0.50])", true); + expect("color.equal(['G', 0.50], ['CMYK', 0, 0, 0, 0])", false); + expect("color.equal(['G', 0.50], ['CMYK', 0, 0, 0, 0.50])", true); + + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['T'])", false); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['G', 0])", false); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['G', 0.25])", true); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['RGB', 0, 0, 0])", false); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['RGB', 0.25, 0.25, 0.25])", true); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['CMYK', 0, 0, 0, 0])", false); + expect("color.equal(['RGB', 0.25, 0.25, 0.25], ['CMYK', 0.75, 0.75, 0.75, 0.75])", true); + + expect("color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['T'])", false); + expect("color.equal(['CMYK', 0.00, 0.25, 0.25, 0.50], ['G', 0])", false); + expect("color.equal(['CMYK', 0.00, 0.00, 0.00, 0.50], ['G', 0.50])", true); + expect("color.equal(['CMYK', 0.75, 0.50, 0.25, 0.25], ['RGB', 0, 0, 0])", false); + expect("color.equal(['CMYK', 0.75, 0.50, 0.25, 0.25], ['RGB', 0.25, 0.50, 0.75])", true); + expect("color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['CMYK', 0, 0, 0, 0])", false); + expect("color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['CMYK', 0.25, 0.25, 0.25, 0.50])", true); +} catch (e) { + app.alert("Truly unexpected error: " + e); +} +endstream +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF diff --git a/testing/resources/javascript/color_methods_expected.txt b/testing/resources/javascript/color_methods_expected.txt new file mode 100644 index 0000000000..2552a5e4ba --- /dev/null +++ b/testing/resources/javascript/color_methods_expected.txt @@ -0,0 +1,57 @@ +Alert: PASS: color.convert() threw error color.convert: Incorrect number of parameters passed to function. +Alert: PASS: color.convert(1) threw error color.convert: Incorrect number of parameters passed to function. +Alert: PASS: color.convert(undefined, 'RGB') threw error color.convert: Incorrect parameter type. +Alert: PASS: color.convert('BOGUS', 'RGB') threw error color.convert: Incorrect parameter type. +Alert: PASS: color.convert('{}', 'RGB') threw error color.convert: Incorrect parameter type. +Alert: PASS: color.convert(['T'], 'BOGUS') = T +Alert: PASS: color.convert(['T'], 'T') = T +Alert: PASS: color.convert(['T'], 'G') = T +Alert: PASS: color.convert(['T'], 'RGB') = T +Alert: PASS: color.convert(['T'], 'CMYK') = T +Alert: PASS: color.convert(['G', 0.50], 'BOGUS') = T +Alert: PASS: color.convert(['G', 0.50], 'T') = T +Alert: PASS: color.convert(['G', 0.50], 'G') = G,0.5 +Alert: PASS: color.convert(['G', 0.50], 'RGB') = RGB,0.5,0.5,0.5 +Alert: PASS: color.convert(['G', 0.50], 'CMYK') = CMYK,0,0,0,0.5 +Alert: PASS: color.convert(['RGB', 0.25, 0.50, 0.75], 'BOGUS') = T +Alert: PASS: color.convert(['RGB', 0.25, 0.50, 0.75], 'T') = T +Alert: PASS: color.convert(['RGB', 1.00, 1.00, 1.00], 'G') = G,1 +Alert: PASS: color.convert(['RGB', 0.25, 0.50, 0.75], 'RGB') = RGB,0.25,0.5,0.75 +Alert: PASS: color.convert(['RGB', 0.25, 0.50, 0.75], 'CMYK') = CMYK,0.75,0.5,0.25,0.25 +Alert: PASS: color.convert(['CMYK',0.25,0.25,0.25,0.50], 'BOGUS') = T +Alert: PASS: color.convert(['CMYK',0.25,0.25,0.25,0.50], 'T') = T +Alert: PASS: color.convert(['CMYK',0.25,0.25,0.25,0.50], 'G') = G,0.25 +Alert: PASS: color.convert(['CMYK',0.25,0.25,0.25,0.50], 'RGB') = RGB,0.25,0.25,0.25 +Alert: PASS: color.convert(['CMYK',0.25,0.25,0.25,0.50], 'CMYK') = CMYK,0.25,0.25,0.25,0.5 +Alert: PASS: color.equal() threw error color.equal: Incorrect number of parameters passed to function. +Alert: PASS: color.equal(1) threw error color.equal: Incorrect number of parameters passed to function. +Alert: PASS: color.equal(undefined, undefined) threw error color.equal: Incorrect parameter type. +Alert: PASS: color.equal(undefined, 'BOGUS') threw error color.equal: Incorrect parameter type. +Alert: PASS: color.equal('BOGUS', 'BOGUS') threw error color.equal: Incorrect parameter type. +Alert: PASS: color.equal('BOGUS', ['T']) threw error color.equal: Incorrect parameter type. +Alert: PASS: color.equal(['T'], 'BOGUS') threw error color.equal: Incorrect parameter type. +Alert: PASS: color.equal(['T'], ['T']) = true +Alert: PASS: color.equal(['T'], ['G', 0]) = false +Alert: PASS: color.equal(['T'], ['RGB', 0, 0, 0]) = false +Alert: PASS: color.equal(['T'], ['CMYK', 0, 0, 0, 0]) = false +Alert: PASS: color.equal(['G', 0.50], ['T']) = false +Alert: PASS: color.equal(['G', 0.50], ['G', 0]) = false +Alert: PASS: color.equal(['G', 0.50], ['G', 0.50]) = true +Alert: PASS: color.equal(['G', 0.50], ['RGB', 0, 0, 0]) = false +Alert: PASS: color.equal(['G', 0.50], ['RGB', 0.50, 0.50, 0.50]) = true +Alert: PASS: color.equal(['G', 0.50], ['CMYK', 0, 0, 0, 0]) = false +Alert: PASS: color.equal(['G', 0.50], ['CMYK', 0, 0, 0, 0.50]) = true +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['T']) = false +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['G', 0]) = false +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['G', 0.25]) = true +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['RGB', 0, 0, 0]) = false +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['RGB', 0.25, 0.25, 0.25]) = true +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['CMYK', 0, 0, 0, 0]) = false +Alert: PASS: color.equal(['RGB', 0.25, 0.25, 0.25], ['CMYK', 0.75, 0.75, 0.75, 0.75]) = true +Alert: PASS: color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['T']) = false +Alert: PASS: color.equal(['CMYK', 0.00, 0.25, 0.25, 0.50], ['G', 0]) = false +Alert: PASS: color.equal(['CMYK', 0.00, 0.00, 0.00, 0.50], ['G', 0.50]) = true +Alert: PASS: color.equal(['CMYK', 0.75, 0.50, 0.25, 0.25], ['RGB', 0, 0, 0]) = false +Alert: PASS: color.equal(['CMYK', 0.75, 0.50, 0.25, 0.25], ['RGB', 0.25, 0.50, 0.75]) = true +Alert: PASS: color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['CMYK', 0, 0, 0, 0]) = false +Alert: PASS: color.equal(['CMYK', 0.25, 0.25, 0.25, 0.50], ['CMYK', 0.25, 0.25, 0.25, 0.50]) = true |