255 lines
9.3 KiB
C++
255 lines
9.3 KiB
C++
// Copyright 2017 The PDFium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
|
|
|
|
#include "fxjs/xfa/cjx_tree.h"
|
|
|
|
#include <vector>
|
|
|
|
#include "fxjs/fxv8.h"
|
|
#include "fxjs/js_resources.h"
|
|
#include "fxjs/xfa/cfxjse_class.h"
|
|
#include "fxjs/xfa/cfxjse_engine.h"
|
|
#include "third_party/base/numerics/safe_conversions.h"
|
|
#include "v8/include/cppgc/allocation.h"
|
|
#include "v8/include/v8-object.h"
|
|
#include "v8/include/v8-primitive.h"
|
|
#include "xfa/fxfa/parser/cxfa_arraynodelist.h"
|
|
#include "xfa/fxfa/parser/cxfa_attachnodelist.h"
|
|
#include "xfa/fxfa/parser/cxfa_document.h"
|
|
#include "xfa/fxfa/parser/cxfa_node.h"
|
|
#include "xfa/fxfa/parser/cxfa_object.h"
|
|
|
|
const CJX_MethodSpec CJX_Tree::MethodSpecs[] = {
|
|
{"resolveNode", resolveNode_static},
|
|
{"resolveNodes", resolveNodes_static}};
|
|
|
|
CJX_Tree::CJX_Tree(CXFA_Object* obj) : CJX_Object(obj) {
|
|
DefineMethods(MethodSpecs);
|
|
}
|
|
|
|
CJX_Tree::~CJX_Tree() = default;
|
|
|
|
bool CJX_Tree::DynamicTypeIs(TypeTag eType) const {
|
|
return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
|
|
}
|
|
|
|
CJS_Result CJX_Tree::resolveNode(
|
|
CFXJSE_Engine* runtime,
|
|
const std::vector<v8::Local<v8::Value>>& params) {
|
|
if (params.size() != 1)
|
|
return CJS_Result::Failure(JSMessage::kParamError);
|
|
|
|
WideString wsExpression = runtime->ToWideString(params[0]);
|
|
CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
|
|
CXFA_Object* pRefNode = GetXFAObject();
|
|
if (pRefNode->GetElementType() == XFA_Element::Xfa)
|
|
pRefNode = pScriptContext->GetThisObject();
|
|
|
|
absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
|
|
pScriptContext->ResolveObjects(
|
|
ToNode(pRefNode), wsExpression.AsStringView(),
|
|
Mask<XFA_ResolveFlag>{
|
|
XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
|
|
XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
|
|
XFA_ResolveFlag::kSiblings});
|
|
if (!maybeResult.has_value())
|
|
return CJS_Result::Success(runtime->NewNull());
|
|
|
|
if (maybeResult.value().type == CFXJSE_Engine::ResolveResult::Type::kNodes) {
|
|
return CJS_Result::Success(
|
|
GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
|
|
maybeResult.value().objects.front().Get()));
|
|
}
|
|
|
|
if (!maybeResult.value().script_attribute.callback ||
|
|
maybeResult.value().script_attribute.eValueType !=
|
|
XFA_ScriptType::Object) {
|
|
return CJS_Result::Success(runtime->NewNull());
|
|
}
|
|
|
|
v8::Local<v8::Value> pValue;
|
|
CJX_Object* jsObject = maybeResult.value().objects.front()->JSObject();
|
|
(*maybeResult.value().script_attribute.callback)(
|
|
runtime->GetIsolate(), jsObject, &pValue, false,
|
|
maybeResult.value().script_attribute.attribute);
|
|
return CJS_Result::Success(pValue);
|
|
}
|
|
|
|
CJS_Result CJX_Tree::resolveNodes(
|
|
CFXJSE_Engine* runtime,
|
|
const std::vector<v8::Local<v8::Value>>& params) {
|
|
if (params.size() != 1)
|
|
return CJS_Result::Failure(JSMessage::kParamError);
|
|
|
|
CXFA_Object* refNode = GetXFAObject();
|
|
if (refNode->GetElementType() == XFA_Element::Xfa)
|
|
refNode = GetDocument()->GetScriptContext()->GetThisObject();
|
|
|
|
CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
|
|
const Mask<XFA_ResolveFlag> kFlags = {
|
|
XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
|
|
XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
|
|
XFA_ResolveFlag::kSiblings};
|
|
return CJS_Result::Success(ResolveNodeList(pScriptContext->GetIsolate(),
|
|
runtime->ToWideString(params[0]),
|
|
kFlags, ToNode(refNode)));
|
|
}
|
|
|
|
void CJX_Tree::all(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
|
|
XFA_ResolveFlag::kALL};
|
|
WideString wsExpression = GetAttributeByEnum(XFA_Attribute::Name) + L"[*]";
|
|
*pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
|
|
}
|
|
|
|
void CJX_Tree::classAll(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kSiblings,
|
|
XFA_ResolveFlag::kALL};
|
|
WideString wsExpression =
|
|
L"#" + WideString::FromASCII(GetXFAObject()->GetClassName()) + L"[*]";
|
|
*pValue = ResolveNodeList(pIsolate, wsExpression, kFlags, nullptr);
|
|
}
|
|
|
|
void CJX_Tree::nodes(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
WideString wsMessage = L"Unable to set ";
|
|
FXJSE_ThrowMessage(pIsolate, wsMessage.ToUTF8().AsStringView());
|
|
return;
|
|
}
|
|
|
|
CXFA_Document* pDoc = GetDocument();
|
|
auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_AttachNodeList>(
|
|
pDoc->GetHeap()->GetAllocationHandle(), pDoc, GetXFANode());
|
|
pDoc->GetNodeOwner()->PersistList(pNodeList);
|
|
|
|
CFXJSE_Engine* pEngine = pDoc->GetScriptContext();
|
|
*pValue = pNodeList->JSObject()->NewBoundV8Object(
|
|
pIsolate, pEngine->GetJseNormalClass()->GetTemplate(pIsolate));
|
|
}
|
|
|
|
void CJX_Tree::parent(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
|
|
CXFA_Node* pParent = GetXFANode()->GetParent();
|
|
*pValue = pParent ? GetDocument()
|
|
->GetScriptContext()
|
|
->GetOrCreateJSBindingFromMap(pParent)
|
|
.As<v8::Value>()
|
|
: fxv8::NewNullHelper(pIsolate).As<v8::Value>();
|
|
}
|
|
|
|
void CJX_Tree::index(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
|
|
CXFA_Node* pNode = GetXFANode();
|
|
size_t iIndex = pNode ? pNode->GetIndexByName() : 0;
|
|
*pValue = fxv8::NewNumberHelper(pIsolate,
|
|
pdfium::base::checked_cast<int32_t>(iIndex));
|
|
}
|
|
|
|
void CJX_Tree::classIndex(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
|
|
CXFA_Node* pNode = GetXFANode();
|
|
size_t iIndex = pNode ? pNode->GetIndexByClassName() : 0;
|
|
*pValue = fxv8::NewNumberHelper(pIsolate,
|
|
pdfium::base::checked_cast<int32_t>(iIndex));
|
|
}
|
|
|
|
void CJX_Tree::somExpression(v8::Isolate* pIsolate,
|
|
v8::Local<v8::Value>* pValue,
|
|
bool bSetting,
|
|
XFA_Attribute eAttribute) {
|
|
if (bSetting) {
|
|
ThrowInvalidPropertyException(pIsolate);
|
|
return;
|
|
}
|
|
|
|
ByteString bsSOMExpression = GetXFAObject()->GetSOMExpression().ToUTF8();
|
|
*pValue = fxv8::NewStringHelper(pIsolate, bsSOMExpression.AsStringView());
|
|
}
|
|
|
|
v8::Local<v8::Value> CJX_Tree::ResolveNodeList(v8::Isolate* pIsolate,
|
|
WideString wsExpression,
|
|
Mask<XFA_ResolveFlag> dwFlag,
|
|
CXFA_Node* refNode) {
|
|
if (!refNode)
|
|
refNode = GetXFANode();
|
|
|
|
CXFA_Document* pDoc = GetDocument();
|
|
auto* pNodeList = cppgc::MakeGarbageCollected<CXFA_ArrayNodeList>(
|
|
pDoc->GetHeap()->GetAllocationHandle(), pDoc);
|
|
pDoc->GetNodeOwner()->PersistList(pNodeList);
|
|
|
|
CFXJSE_Engine* pScriptContext = pDoc->GetScriptContext();
|
|
absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
|
|
pScriptContext->ResolveObjects(refNode, wsExpression.AsStringView(),
|
|
dwFlag);
|
|
|
|
if (maybeResult.has_value()) {
|
|
if (maybeResult.value().type ==
|
|
CFXJSE_Engine::ResolveResult::Type::kNodes) {
|
|
for (auto& pObject : maybeResult.value().objects) {
|
|
if (pObject->IsNode())
|
|
pNodeList->Append(pObject->AsNode());
|
|
}
|
|
} else {
|
|
if (maybeResult.value().script_attribute.callback &&
|
|
maybeResult.value().script_attribute.eValueType ==
|
|
XFA_ScriptType::Object) {
|
|
for (auto& pObject : maybeResult.value().objects) {
|
|
v8::Local<v8::Value> innerValue;
|
|
CJX_Object* jsObject = pObject->JSObject();
|
|
(*maybeResult.value().script_attribute.callback)(
|
|
pIsolate, jsObject, &innerValue, false,
|
|
maybeResult.value().script_attribute.attribute);
|
|
CXFA_Object* obj =
|
|
CFXJSE_Engine::ToObject(pScriptContext->GetIsolate(), innerValue);
|
|
if (obj->IsNode())
|
|
pNodeList->Append(obj->AsNode());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pNodeList->JSObject()->NewBoundV8Object(
|
|
pIsolate, pScriptContext->GetJseNormalClass()->GetTemplate(pIsolate));
|
|
}
|