/* * Copyright (C) 2015-2018 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. AND ITS CONTRIBUTORS ``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 ITS 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 "HTMLAttachmentElement.h" #if ENABLE(ATTACHMENT_ELEMENT) #include "DOMURL.h" #include "Document.h" #include "Editor.h" #include "File.h" #include "Frame.h" #include "HTMLImageElement.h" #include "HTMLNames.h" #include "MIMETypeRegistry.h" #include "RenderAttachment.h" #include "SharedBuffer.h" #include #include #include #include #if PLATFORM(COCOA) #include "UTIUtilities.h" #endif namespace WebCore { WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLAttachmentElement); using namespace HTMLNames; HTMLAttachmentElement::HTMLAttachmentElement(const QualifiedName& tagName, Document& document) : HTMLElement(tagName, document) { ASSERT(hasTagName(attachmentTag)); } HTMLAttachmentElement::~HTMLAttachmentElement() = default; Ref HTMLAttachmentElement::create(const QualifiedName& tagName, Document& document) { return adoptRef(*new HTMLAttachmentElement(tagName, document)); } RenderPtr HTMLAttachmentElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&) { return createRenderer(*this, WTFMove(style)); } const String& HTMLAttachmentElement::getAttachmentIdentifier(HTMLImageElement& image) { if (auto attachment = image.attachmentElement()) return attachment->uniqueIdentifier(); auto& document = image.document(); auto attachment = create(HTMLNames::attachmentTag, document); auto& identifier = attachment->ensureUniqueIdentifier(); document.registerAttachmentIdentifier(identifier); image.setAttachmentElement(WTFMove(attachment)); return identifier; } void HTMLAttachmentElement::copyNonAttributePropertiesFromElement(const Element& source) { m_uniqueIdentifier = downcast(source).uniqueIdentifier(); HTMLElement::copyNonAttributePropertiesFromElement(source); } URL HTMLAttachmentElement::archiveResourceURL(const String& identifier) { auto resourceURL = URL({ }, "applewebdata://attachment/"_s); resourceURL.setPath(identifier); return resourceURL; } File* HTMLAttachmentElement::file() const { return m_file.get(); } URL HTMLAttachmentElement::blobURL() const { return { { }, attributeWithoutSynchronization(HTMLNames::webkitattachmentbloburlAttr).string() }; } void HTMLAttachmentElement::setFile(RefPtr&& file, UpdateDisplayAttributes updateAttributes) { m_file = WTFMove(file); if (updateAttributes == UpdateDisplayAttributes::Yes) { if (m_file) { setAttributeWithoutSynchronization(HTMLNames::titleAttr, m_file->name()); setAttributeWithoutSynchronization(HTMLNames::subtitleAttr, PAL::fileSizeDescription(m_file->size())); setAttributeWithoutSynchronization(HTMLNames::typeAttr, m_file->type()); } else { removeAttribute(HTMLNames::titleAttr); removeAttribute(HTMLNames::subtitleAttr); removeAttribute(HTMLNames::typeAttr); } } if (auto* renderer = this->renderer()) renderer->invalidate(); } Node::InsertedIntoAncestorResult HTMLAttachmentElement::insertedIntoAncestor(InsertionType type, ContainerNode& ancestor) { auto result = HTMLElement::insertedIntoAncestor(type, ancestor); if (type.connectedToDocument) document().didInsertAttachmentElement(*this); return result; } void HTMLAttachmentElement::removedFromAncestor(RemovalType type, ContainerNode& ancestor) { HTMLElement::removedFromAncestor(type, ancestor); if (type.disconnectedFromDocument) document().didRemoveAttachmentElement(*this); } const String& HTMLAttachmentElement::ensureUniqueIdentifier() { if (m_uniqueIdentifier.isEmpty()) m_uniqueIdentifier = createCanonicalUUIDString(); return m_uniqueIdentifier; } bool HTMLAttachmentElement::hasEnclosingImage() const { return is(shadowHost()); } void HTMLAttachmentElement::parseAttribute(const QualifiedName& name, const AtomString& value) { if (name == progressAttr || name == subtitleAttr || name == titleAttr || name == typeAttr) { if (auto* renderer = this->renderer()) renderer->invalidate(); } HTMLElement::parseAttribute(name, value); } String HTMLAttachmentElement::attachmentTitle() const { auto& title = attributeWithoutSynchronization(titleAttr); if (!title.isEmpty()) return title; return m_file ? m_file->name() : String(); } String HTMLAttachmentElement::attachmentTitleForDisplay() const { auto title = attachmentTitle(); auto indexOfLastDot = title.reverseFind('.'); if (indexOfLastDot == notFound) return title; return makeString( leftToRightMark, firstStrongIsolate, StringView(title).left(indexOfLastDot), popDirectionalIsolate, StringView(title).substring(indexOfLastDot) ); } String HTMLAttachmentElement::attachmentType() const { return attributeWithoutSynchronization(typeAttr); } String HTMLAttachmentElement::attachmentPath() const { return attributeWithoutSynchronization(webkitattachmentpathAttr); } void HTMLAttachmentElement::updateAttributes(std::optional&& newFileSize, const String& newContentType, const String& newFilename) { if (!newFilename.isNull()) setAttributeWithoutSynchronization(HTMLNames::titleAttr, newFilename); else removeAttribute(HTMLNames::titleAttr); if (!newContentType.isNull()) setAttributeWithoutSynchronization(HTMLNames::typeAttr, newContentType); else removeAttribute(HTMLNames::typeAttr); if (newFileSize) setAttributeWithoutSynchronization(HTMLNames::subtitleAttr, PAL::fileSizeDescription(*newFileSize)); else removeAttribute(HTMLNames::subtitleAttr); if (auto* renderer = this->renderer()) renderer->invalidate(); } static bool mimeTypeIsSuitableForInlineImageAttachment(const String& mimeType) { return MIMETypeRegistry::isSupportedImageMIMEType(mimeType) || MIMETypeRegistry::isPDFMIMEType(mimeType); } void HTMLAttachmentElement::updateEnclosingImageWithData(const String& contentType, Ref&& buffer) { auto* hostElement = shadowHost(); if (!is(hostElement) || !buffer->size()) return; String mimeType = contentType; #if PLATFORM(COCOA) if (isDeclaredUTI(contentType)) mimeType = MIMETypeFromUTI(contentType); #endif if (!mimeTypeIsSuitableForInlineImageAttachment(mimeType)) return; hostElement->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document(), Blob::create(&document(), buffer->extractData(), mimeType))); } void HTMLAttachmentElement::updateThumbnail(const RefPtr& thumbnail) { m_thumbnail = thumbnail; if (auto* renderer = this->renderer()) renderer->invalidate(); } } // namespace WebCore #endif // ENABLE(ATTACHMENT_ELEMENT)