From 5ad45e2f68bb796c562302e9fc2d963c279334c7 Mon Sep 17 00:00:00 2001 From: Dan Sinclair Date: Thu, 10 May 2018 20:26:35 +0000 Subject: Cleanup formcalc method generation This CL simplifies the FormCalc method call generation when converted to JavaScript. Currently we output the same chunk of code to run the given method on an array or object per method call. This CL pulls out the common execution code to a pfm_method_runner function which is used instead. An embedder test has been added to verify that method invocation from formcalc works correctly. Bug: chromium:814848 Change-Id: I1ec052eab051053fedcb464d57e0e15228b8c5a2 Reviewed-on: https://pdfium-review.googlesource.com/32372 Reviewed-by: Henrique Nakashima Commit-Queue: dsinclair --- fxjs/cfxjse_formcalc_context_embeddertest.cpp | 11 +++ testing/xfa_js_embedder_test.cpp | 2 +- xfa/fxfa/fm2js/cxfa_fmexpression.cpp | 11 ++- xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp | 128 ++++++++++++++++---------- xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp | 18 +--- 5 files changed, 105 insertions(+), 65 deletions(-) diff --git a/fxjs/cfxjse_formcalc_context_embeddertest.cpp b/fxjs/cfxjse_formcalc_context_embeddertest.cpp index d48d5cc445..a7efc14d20 100644 --- a/fxjs/cfxjse_formcalc_context_embeddertest.cpp +++ b/fxjs/cfxjse_formcalc_context_embeddertest.cpp @@ -1444,3 +1444,14 @@ TEST_F(CFXJSE_FormCalcContextEmbedderTest, InvalidFunctions) { EXPECT_FALSE(ExecuteSilenceFailure(tests[i])); } } + +TEST_F(CFXJSE_FormCalcContextEmbedderTest, MethodCall) { + ASSERT_TRUE(OpenDocument("simple_xfa.pdf")); + + const char test[] = {"$form.form1.TextField11.getAttribute(\"h\")"}; + EXPECT_TRUE(Execute(test)); + + CFXJSE_Value* value = GetValue(); + EXPECT_TRUE(value->IsString()); + EXPECT_STREQ("12.7mm", value->ToString().c_str()); +} diff --git a/testing/xfa_js_embedder_test.cpp b/testing/xfa_js_embedder_test.cpp index fe54621a2b..97009f34c2 100644 --- a/testing/xfa_js_embedder_test.cpp +++ b/testing/xfa_js_embedder_test.cpp @@ -76,7 +76,7 @@ bool XFAJSEmbedderTest::Execute(const ByteStringView& input) { CFXJSE_Value msg(GetIsolate()); value_->GetObjectPropertyByIdx(1, &msg); - fprintf(stderr, "JS: %.*s\n", static_cast(input.GetLength()), + fprintf(stderr, "FormCalc: %.*s\n", static_cast(input.GetLength()), input.unterminated_c_str()); // If the parsing of the input fails, then v8 will not run, so there will be // no value here to print. diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp index a3c65a2203..ef2153d6be 100644 --- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp @@ -89,6 +89,16 @@ bool CXFA_FMAST::ToJavaScript(CFX_WideTextBuf& js) { } js << L"(function() {\n"; + js << L"let pfm_method_runner = function(obj, cb) {\n"; + js << L" if (pfm_rt.is_ary(obj)) {\n"; + js << L" let pfm_method_return = null;\n"; + js << L" for (var idx = obj.length -1; idx > 1; idx--) {\n"; + js << L" pfm_method_return = cb(obj[idx]);\n"; + js << L" }\n"; + js << L" return pfm_method_return;\n"; + js << L" }\n"; + js << L" return cb(obj);\n"; + js << L"};\n"; js << L"var pfm_ret = null;\n"; for (const auto& expr : expressions_) { @@ -100,7 +110,6 @@ bool CXFA_FMAST::ToJavaScript(CFX_WideTextBuf& js) { js << L"return pfm_rt.get_val(pfm_ret);\n"; js << L"}).call(this);"; - return !CXFA_IsTooBig(js); } diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp index 0dba59c3bb..81fae08384 100644 --- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp @@ -42,6 +42,16 @@ TEST(CXFA_FMParserTest, CommentOnlyIsError) { TEST(CXFA_FMParserTest, CommentThenValue) { const wchar_t ret[] = L"(function() {\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" + L"};\n" L"var pfm_ret = null;\n" L"pfm_ret = 12;\n" L"return pfm_rt.get_val(pfm_ret);\n" @@ -75,6 +85,16 @@ TEST(CXFA_FMParserTest, Parse) { const wchar_t ret[] = L"(function() {\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" + L"};\n" L"var pfm_ret = null;\n" L"if (pfm_rt.is_obj(this))\n{\n" L"pfm_rt.asgn_val_op(this, pfm_rt.Avg(pfm_rt.neg_op(3), 5, " @@ -159,6 +179,16 @@ TEST(CXFA_FMParserTest, ParseFuncWithParams) { const wchar_t ret[] = { L"(function() {\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" + L"};\n" L"var pfm_ret = null;\n" L"function MyFunction(param1, param2) {\n" L"var pfm_ret = null;\n" @@ -187,6 +217,16 @@ TEST(CXFA_FMParserTest, ParseFuncWithoutParams) { const wchar_t ret[] = { L"(function() {\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" + L"};\n" L"var pfm_ret = null;\n" L"function MyFunction() {\n" L"var pfm_ret = null;\n" @@ -262,20 +302,22 @@ TEST(CXFA_FMParserTest, ParseCallSmall) { const wchar_t input[] = {L"i.f(O)"}; const wchar_t ret[] = { L"(function() {\n" - L"var pfm_ret = null;\n" - L"pfm_ret = pfm_rt.get_val((function () {\n" - L"let pfm_cb = function(obj) {\n" - L"return obj.f(pfm_rt.get_val(O));\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" L"};\n" - L"if (pfm_rt.is_ary(i)) {\n" - L"let method_return_value = null;\n" - L"for (var index = i.length - 1; index > 1; index--) {\n" - L"method_return_value = pfm_cb(i[index]);\n" - L"}\n" - L"return method_return_value;\n" - L"} else {\n" - L"return pfm_cb(i);\n" - L"}}).call(this));\n" + L"var pfm_ret = null;\n" + L"pfm_ret = pfm_rt.get_val((function() {\n" + L" return pfm_method_runner(i, function(obj) {\n" + L" return obj.f(pfm_rt.get_val(O));\n" + L" });\n" + L"}).call(this));\n" L"return pfm_rt.get_val(pfm_ret);\n" L"}).call(this);"}; @@ -293,44 +335,30 @@ TEST(CXFA_FMParserTest, ParseCallBig) { const wchar_t input[] = {L"i.f(O.e(O.e(O)))"}; const wchar_t ret[] = { L"(function() {\n" - L"var pfm_ret = null;\n" - L"pfm_ret = pfm_rt.get_val((function () {\n" - L"let pfm_cb = function(obj) {\n" - L"return obj.f(pfm_rt.get_val((function () {\n" - L"let pfm_cb = function(obj) {\n" - L"return obj.e(pfm_rt.get_val((function () {\n" - L"let pfm_cb = function(obj) {\n" - L"return obj.e(pfm_rt.get_val(O));\n" - L"};\n" - L"if (pfm_rt.is_ary(O)) {\n" - L"let method_return_value = null;\n" - L"for (var index = O.length - 1; index > 1; index--) {\n" - L"method_return_value = pfm_cb(O[index]);\n" - L"}\n" - L"return method_return_value;\n" - L"} else {\n" - L"return pfm_cb(O);\n" - L"}}).call(this)));\n" + L"let pfm_method_runner = function(obj, cb) {\n" + L" if (pfm_rt.is_ary(obj)) {\n" + L" let pfm_method_return = null;\n" + L" for (var idx = obj.length -1; idx > 1; idx--) {\n" + L" pfm_method_return = cb(obj[idx]);\n" + L" }\n" + L" return pfm_method_return;\n" + L" }\n" + L" return cb(obj);\n" L"};\n" - L"if (pfm_rt.is_ary(O)) {\n" - L"let method_return_value = null;\n" - L"for (var index = O.length - 1; index > 1; index--) {\n" - L"method_return_value = pfm_cb(O[index]);\n" - L"}\n" - L"return method_return_value;\n" - L"} else {\n" - L"return pfm_cb(O);\n" - L"}}).call(this)));\n" - L"};\n" - L"if (pfm_rt.is_ary(i)) {\n" - L"let method_return_value = null;\n" - L"for (var index = i.length - 1; index > 1; index--) {\n" - L"method_return_value = pfm_cb(i[index]);\n" - L"}\n" - L"return method_return_value;\n" - L"} else {\n" - L"return pfm_cb(i);\n" - L"}}).call(this));\n" + L"var pfm_ret = null;\n" + L"pfm_ret = pfm_rt.get_val((function() {\n" + L" return pfm_method_runner(i, function(obj) {\n" + L" return obj.f(pfm_rt.get_val((function() {\n" + L" return pfm_method_runner(O, function(obj) {\n" + L" return obj.e(pfm_rt.get_val((function() {\n" + L" return pfm_method_runner(O, function(obj) {\n" + L" return obj.e(pfm_rt.get_val(O));\n" + L" });\n" + L"}).call(this)));\n" + L" });\n" + L"}).call(this)));\n" + L" });\n" + L"}).call(this));\n" L"return pfm_rt.get_val(pfm_ret);\n" L"}).call(this);"}; diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp index 069899311e..e34d4ba127 100644 --- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp +++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp @@ -676,22 +676,14 @@ bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& js, if (!m_pExp1->ToJavaScript(buf, ReturnType::kInfered)) return false; - js << L"(function () {\n"; - js << L"let pfm_cb = function(obj) {\n"; - js << L"return obj."; + js << L"(function() {\n"; + js << L" return pfm_method_runner(" << buf << L", function(obj) {\n"; + js << L" return obj."; if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered)) return false; js << L";\n"; - js << L"};\n"; - js << L"if (pfm_rt.is_ary(" << buf << L")) {\n"; - js << L"let method_return_value = null;\n"; - js << L"for (var index = " << buf << L".length - 1; index > 1; index--) {\n"; - js << L"method_return_value = pfm_cb(" << buf << L"[index]);\n"; - js << L"}\n"; - js << L"return method_return_value;\n"; - js << L"} else {\n"; - js << L"return pfm_cb(" << buf << L");\n"; - js << L"}}).call(this)"; + js << L" });\n"; + js << L"}).call(this)"; return !CXFA_IsTooBig(js); } -- cgit v1.2.3