| /* |
| * Copyright (C) 2022, 2023 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "CSSStyleSheetObservableArray.h" |
| |
| #include "Document.h" |
| #include "JSCSSStyleSheet.h" |
| #include "JSDOMConvert.h" |
| #include "ShadowRoot.h" |
| #include "TreeScope.h" |
| |
| namespace WebCore { |
| |
| Ref<CSSStyleSheetObservableArray> CSSStyleSheetObservableArray::create(ContainerNode& treeScope) |
| { |
| return adoptRef(*new CSSStyleSheetObservableArray(treeScope)); |
| } |
| |
| CSSStyleSheetObservableArray::CSSStyleSheetObservableArray(ContainerNode& treeScope) |
| : m_treeScope(treeScope) |
| { |
| ASSERT(is<Document>(treeScope) || is<ShadowRoot>(treeScope)); |
| } |
| |
| bool CSSStyleSheetObservableArray::setValueAt(JSC::JSGlobalObject* lexicalGlobalObject, unsigned index, JSC::JSValue value) |
| { |
| auto& vm = lexicalGlobalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| RELEASE_ASSERT(index <= m_sheets.size()); |
| |
| auto sheetConversionResult = convert<IDLInterface<CSSStyleSheet>>(*lexicalGlobalObject, value); |
| if (sheetConversionResult.hasException(scope)) [[unlikely]] |
| return false; |
| |
| if (auto exception = shouldThrowWhenAddingSheet(sheetConversionResult.returnValue())) { |
| throwException(lexicalGlobalObject, scope, createDOMException(*lexicalGlobalObject, WTF::move(*exception))); |
| return false; |
| } |
| |
| if (index == m_sheets.size()) |
| m_sheets.append(sheetConversionResult.returnValue()); |
| else |
| m_sheets[index] = sheetConversionResult.returnValue(); |
| |
| didAddSheet(sheetConversionResult.releaseReturnValue()); |
| return true; |
| } |
| |
| void CSSStyleSheetObservableArray::removeLast() |
| { |
| RELEASE_ASSERT(!m_sheets.isEmpty()); |
| auto sheet = m_sheets.takeLast(); |
| willRemoveSheet(sheet); |
| } |
| |
| void CSSStyleSheetObservableArray::shrinkTo(unsigned length) |
| { |
| RELEASE_ASSERT(length <= m_sheets.size()); |
| m_sheets.shrink(length); |
| } |
| |
| JSC::JSValue CSSStyleSheetObservableArray::valueAt(JSC::JSGlobalObject* lexicalGlobalObject, unsigned index) const |
| { |
| if (index >= m_sheets.size()) |
| return JSC::jsUndefined(); |
| return toJS(lexicalGlobalObject, JSC::jsCast<JSDOMGlobalObject*>(lexicalGlobalObject), m_sheets[index]); |
| } |
| |
| ExceptionOr<void> CSSStyleSheetObservableArray::setSheets(Vector<Ref<CSSStyleSheet>>&& sheets) |
| { |
| for (auto& sheet : sheets) { |
| if (auto exception = shouldThrowWhenAddingSheet(sheet)) |
| return WTF::move(*exception); |
| } |
| |
| for (auto& sheet : m_sheets) |
| willRemoveSheet(sheet); |
| m_sheets = WTF::move(sheets); |
| for (auto& sheet : m_sheets) |
| didAddSheet(sheet); |
| |
| return { }; |
| } |
| |
| std::optional<Exception> CSSStyleSheetObservableArray::shouldThrowWhenAddingSheet(const CSSStyleSheet& sheet) const |
| { |
| if (!sheet.wasConstructedByJS()) |
| return Exception { ExceptionCode::NotAllowedError, "Sheet needs to be constructed by JavaScript"_s }; |
| RefPtr treeScope = this->treeScope(); |
| if (!treeScope || sheet.constructorDocument() != &treeScope->documentScope()) |
| return Exception { ExceptionCode::NotAllowedError, "Sheet constructor document doesn't match"_s }; |
| return std::nullopt; |
| } |
| |
| TreeScope* CSSStyleSheetObservableArray::treeScope() const |
| { |
| if (!m_treeScope) |
| return nullptr; |
| if (auto* shadowRoot = dynamicDowncast<ShadowRoot>(*m_treeScope)) |
| return shadowRoot; |
| return &downcast<Document>(*m_treeScope); |
| } |
| |
| void CSSStyleSheetObservableArray::didAddSheet(CSSStyleSheet& sheet) |
| { |
| if (m_treeScope) |
| sheet.addAdoptingTreeScope(*m_treeScope); |
| } |
| |
| void CSSStyleSheetObservableArray::willRemoveSheet(CSSStyleSheet& sheet) |
| { |
| if (m_treeScope) |
| sheet.removeAdoptingTreeScope(*m_treeScope); |
| } |
| |
| } // namespace WebCore |