/* * Copyright (C) 2007-2009, 2011, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include "JSDocument.h" #include "ExceptionCode.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLDocument.h" #include "JSCanvasRenderingContext2D.h" #include "JSDOMConvert.h" #include "JSDOMWindowCustom.h" #include "JSHTMLDocument.h" #include "JSLocation.h" #include "JSXMLDocument.h" #include "Location.h" #include "NodeTraversal.h" #include "SVGDocument.h" #include "ScriptController.h" #include "TouchList.h" #include "XMLDocument.h" #include #if ENABLE(WEBGL) #include "JSWebGLRenderingContextBase.h" #endif #if ENABLE(TOUCH_EVENTS) #include "JSTouch.h" #include "JSTouchList.h" #endif using namespace JSC; namespace WebCore { static inline JSValue createNewDocumentWrapper(ExecState& state, JSDOMGlobalObject& globalObject, Ref&& passedDocument) { auto& document = passedDocument.get(); JSObject* wrapper; if (document.isHTMLDocument()) wrapper = createWrapper(&globalObject, WTFMove(passedDocument)); else if (document.isXMLDocument()) wrapper = createWrapper(&globalObject, WTFMove(passedDocument)); else wrapper = createWrapper(&globalObject, WTFMove(passedDocument)); reportMemoryForDocumentIfFrameless(state, document); return wrapper; } JSObject* cachedDocumentWrapper(ExecState& state, JSDOMGlobalObject& globalObject, Document& document) { if (auto* wrapper = getCachedWrapper(globalObject.world(), document)) return wrapper; auto* window = document.domWindow(); if (!window) return nullptr; // Creating a wrapper for domWindow might have created a wrapper for document as well. return getCachedWrapper(toJSDOMWindow(state.vm(), toJS(&state, *window))->world(), document); } void reportMemoryForDocumentIfFrameless(ExecState& state, Document& document) { // Make sure the document is kept around by the window object, and works right with the back/forward cache. if (document.frame()) return; size_t memoryCost = 0; for (Node* node = &document; node; node = NodeTraversal::next(*node)) memoryCost += node->approximateMemoryCost(); // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. // https://bugs.webkit.org/show_bug.cgi?id=142595 state.heap()->deprecatedReportExtraMemory(memoryCost); } JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref&& document) { return createNewDocumentWrapper(*state, *globalObject, WTFMove(document)); } JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, Document& document) { if (auto* wrapper = cachedDocumentWrapper(*state, *globalObject, document)) return wrapper; return toJSNewlyCreated(state, globalObject, Ref(document)); } #if ENABLE(TOUCH_EVENTS) JSValue JSDocument::createTouchList(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto touchList = TouchList::create(); for (size_t i = 0; i < state.argumentCount(); ++i) { auto* item = JSTouch::toWrapped(vm, state.uncheckedArgument(i)); if (!item) return JSValue::decode(throwArgumentTypeError(state, scope, i, "touches", "Document", "createTouchList", "Touch")); touchList->append(*item); } return toJSNewlyCreated(&state, globalObject(), WTFMove(touchList)); } #endif JSValue JSDocument::getCSSCanvasContext(JSC::ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (UNLIKELY(state.argumentCount() < 4)) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto contextId = state.uncheckedArgument(0).toWTFString(&state); RETURN_IF_EXCEPTION(scope, JSValue()); auto name = state.uncheckedArgument(1).toWTFString(&state); RETURN_IF_EXCEPTION(scope, JSValue()); auto width = convert(state, state.uncheckedArgument(2), IntegerConversionConfiguration::Normal); RETURN_IF_EXCEPTION(scope, JSValue()); auto height = convert(state, state.uncheckedArgument(3), IntegerConversionConfiguration::Normal); RETURN_IF_EXCEPTION(scope, JSValue()); auto* context = wrapped().getCSSCanvasContext(WTFMove(contextId), WTFMove(name), WTFMove(width), WTFMove(height)); if (!context) return jsNull(); #if ENABLE(WEBGL) if (is(*context)) return toJS(&state, globalObject(), downcast(*context)); #endif return toJS(&state, globalObject(), downcast(*context)); } void JSDocument::visitAdditionalChildren(SlotVisitor& visitor) { visitor.addOpaqueRoot(static_cast(&wrapped())); } } // namespace WebCore