JSHTMLDocumentCustom.cpp [plain text]
#include "config.h"
#include "JSHTMLDocument.h"
#include "HTMLIFrameElement.h"
#include "JSDOMWindowCustom.h"
#include "JSHTMLCollection.h"
#include "SegmentedString.h"
using namespace JSC;
namespace WebCore {
using namespace HTMLNames;
JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<HTMLDocument>&& passedDocument)
{
auto& document = passedDocument.get();
auto* wrapper = createWrapper<HTMLDocument>(globalObject, WTFMove(passedDocument));
reportMemoryForDocumentIfFrameless(*state, document);
return wrapper;
}
JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, HTMLDocument& document)
{
if (auto* wrapper = cachedDocumentWrapper(*state, *globalObject, document))
return wrapper;
return toJSNewlyCreated(state, globalObject, Ref<HTMLDocument>(document));
}
bool JSHTMLDocument::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
{
auto& thisObject = *jsCast<JSHTMLDocument*>(object);
ASSERT_GC_OBJECT_INHERITS(object, info());
if (propertyName == "open") {
if (Base::getOwnPropertySlot(&thisObject, state, propertyName, slot))
return true;
slot.setCustom(&thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHTMLDocumentPrototypeFunctionOpen, 2>);
return true;
}
JSValue value;
if (thisObject.nameGetter(state, propertyName, value)) {
slot.setValue(&thisObject, ReadOnly | DontDelete | DontEnum, value);
return true;
}
return Base::getOwnPropertySlot(&thisObject, state, propertyName, slot);
}
bool JSHTMLDocument::nameGetter(ExecState* state, PropertyName propertyName, JSValue& value)
{
auto& document = wrapped();
auto* atomicPropertyName = propertyName.publicName();
if (!atomicPropertyName || !document.hasDocumentNamedItem(*atomicPropertyName))
return false;
if (UNLIKELY(document.documentNamedItemContainsMultipleElements(*atomicPropertyName))) {
auto collection = document.documentNamedItems(atomicPropertyName);
ASSERT(collection->length() > 1);
value = toJS(state, globalObject(), collection);
return true;
}
auto& element = *document.documentNamedItem(*atomicPropertyName);
if (UNLIKELY(is<HTMLIFrameElement>(element))) {
if (auto* frame = downcast<HTMLIFrameElement>(element).contentFrame()) {
value = toJS(state, frame);
return true;
}
}
value = toJS(state, globalObject(), element);
return true;
}
JSValue JSHTMLDocument::all(ExecState& state) const
{
if (auto overwrittenValue = getDirect(state.vm(), Identifier::fromString(&state, "all")))
return overwrittenValue;
return toJS(&state, globalObject(), wrapped().all());
}
void JSHTMLDocument::setAll(ExecState& state, JSValue value)
{
putDirect(state.vm(), Identifier::fromString(&state, "all"), value);
}
static inline Document* findCallingDocument(ExecState& state)
{
CallerFunctor functor;
state.iterate(functor);
auto* callerFrame = functor.callerFrame();
if (!callerFrame)
return nullptr;
return asJSDOMWindow(callerFrame->lexicalGlobalObject())->wrapped().document();
}
JSValue JSHTMLDocument::open(ExecState& state)
{
VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (state.argumentCount() > 2) {
if (auto* frame = wrapped().frame()) {
if (auto* wrapper = toJSDOMWindowShell(frame, currentWorld(&state))) {
auto function = wrapper->get(&state, Identifier::fromString(&state, "open"));
CallData callData;
auto callType = ::getCallData(function, callData);
if (callType == CallType::None)
return throwTypeError(&state, scope);
return JSC::call(&state, function, callType, callData, wrapper, ArgList(&state));
}
}
return jsUndefined();
}
wrapped().open(asJSDOMWindow(state.lexicalGlobalObject())->wrapped().document());
return this;
}
enum NewlineRequirement { DoNotAddNewline, DoAddNewline };
static inline JSValue documentWrite(ExecState& state, JSHTMLDocument& document, NewlineRequirement addNewline)
{
VM& vm = state.vm();
auto scope = DECLARE_THROW_SCOPE(vm);
SegmentedString segmentedString;
size_t argumentCount = state.argumentCount();
for (size_t i = 0; i < argumentCount; ++i) {
segmentedString.append(state.uncheckedArgument(i).toWTFString(&state));
RETURN_IF_EXCEPTION(scope, { });
}
if (addNewline)
segmentedString.append(String { "\n" });
document.wrapped().write(WTFMove(segmentedString), findCallingDocument(state));
return jsUndefined();
}
JSValue JSHTMLDocument::write(ExecState& state)
{
return documentWrite(state, *this, DoNotAddNewline);
}
JSValue JSHTMLDocument::writeln(ExecState& state)
{
return documentWrite(state, *this, DoAddNewline);
}
}