summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2018-05-10 14:01:25 +0000
committerChromium commit bot <commit-bot@chromium.org>2018-05-10 14:01:25 +0000
commit35557c3ce83cc6e26f07cf5d5c520ee6afd39a67 (patch)
tree69a5c3322c00807c3e04fb5172cfc8b4a6c6f694
parentad18d2fba9dd5833a2e34bfe90c8e3c9a485e805 (diff)
downloadpdfium-35557c3ce83cc6e26f07cf5d5c520ee6afd39a67.tar.xz
Change formcalc javascript method output
This CL changes the formcalc JS conversion code so that method calls no longer generate exponential amounts of JavaScript. Previously we'd duplicate the code to call into a method twice. This would then generate twice once for arrays and once for other types of object. This CL changes the code to wrap the actual method call into a JavaScript function which will be used from both the array and non-array calling code. For the referenced bug, the generated JS originally needed a buffer of 365meg to generate. With this CL, it needs a buffer of 7.5k. Bug: chromium:814840 Change-Id: Ibb5993fa52b7c13b20b325cf8848a306f82ae014 Reviewed-on: https://pdfium-review.googlesource.com/32312 Reviewed-by: Henrique Nakashima <hnakashima@chromium.org> Reviewed-by: Ryan Harrison <rharrison@chromium.org> Commit-Queue: dsinclair <dsinclair@chromium.org>
-rw-r--r--xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp86
-rw-r--r--xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp27
2 files changed, 100 insertions, 13 deletions
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
index 1eedebfcca..0dba59c3bb 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
@@ -257,3 +257,89 @@ TEST(CXFA_FMParserTest, ParseDepthWithWideTree) {
EXPECT_TRUE(parser->HasError());
}
}
+
+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"};\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"return pfm_rt.get_val(pfm_ret);\n"
+ L"}).call(this);"};
+
+ auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+ std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+ EXPECT_FALSE(parser->HasError());
+
+ CXFA_FMToJavaScriptDepth::Reset();
+ CFX_WideTextBuf buf;
+ EXPECT_TRUE(ast->ToJavaScript(buf));
+ EXPECT_EQ(ret, buf.AsStringView());
+}
+
+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"};\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"return pfm_rt.get_val(pfm_ret);\n"
+ L"}).call(this);"};
+
+ auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+ std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+ EXPECT_FALSE(parser->HasError());
+
+ CXFA_FMToJavaScriptDepth::Reset();
+ CFX_WideTextBuf buf;
+ EXPECT_TRUE(ast->ToJavaScript(buf));
+ EXPECT_EQ(ret, buf.AsStringView());
+}
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
index 0cfb37e8d0..069899311e 100644
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
@@ -672,25 +672,26 @@ bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf& js,
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
- CFX_WideTextBuf exp2_txt;
- if (!m_pExp2->ToJavaScript(exp2_txt, ReturnType::kInfered))
+ CFX_WideTextBuf buf;
+ if (!m_pExp1->ToJavaScript(buf, ReturnType::kInfered))
return false;
- js << L"(\nfunction ()\n{\n";
- js << L"var method_return_value = null;\n";
- js << L"var accessor_object = ";
- if (!m_pExp1->ToJavaScript(js, ReturnType::kInfered))
+ js << L"(function () {\n";
+ js << L"let pfm_cb = function(obj) {\n";
+ js << L"return obj.";
+ if (!m_pExp2->ToJavaScript(js, ReturnType::kInfered))
return false;
js << L";\n";
- js << L"if (pfm_rt.is_ary(accessor_object))\n{\n";
- js << L"for(var index = accessor_object.length - 1; index > 1; "
- L"index--)\n{\n";
- js << L"method_return_value = accessor_object[index]." << exp2_txt << L";\n";
- js << L"}\n}\nelse\n{\n";
- js << L"method_return_value = accessor_object." << exp2_txt << 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"}\n).call(this)";
+ js << L"} else {\n";
+ js << L"return pfm_cb(" << buf << L");\n";
+ js << L"}}).call(this)";
return !CXFA_IsTooBig(js);
}