Move URL from WebCore to WTF
[WebKit-https.git] / Source / WebCore / html / HTMLAttachmentElement.cpp
1 /*
2  * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "HTMLAttachmentElement.h"
28
29 #if ENABLE(ATTACHMENT_ELEMENT)
30
31 #include "DOMURL.h"
32 #include "Document.h"
33 #include "Editor.h"
34 #include "File.h"
35 #include "Frame.h"
36 #include "HTMLImageElement.h"
37 #include "HTMLNames.h"
38 #include "MIMETypeRegistry.h"
39 #include "RenderAttachment.h"
40 #include "SharedBuffer.h"
41 #include <pal/FileSizeFormatter.h>
42 #include <wtf/IsoMallocInlines.h>
43 #include <wtf/UUID.h>
44 #include <wtf/URLParser.h>
45
46 #if PLATFORM(COCOA)
47 #include "UTIUtilities.h"
48 #endif
49
50 namespace WebCore {
51
52 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLAttachmentElement);
53
54 using namespace HTMLNames;
55
56 HTMLAttachmentElement::HTMLAttachmentElement(const QualifiedName& tagName, Document& document)
57     : HTMLElement(tagName, document)
58 {
59     ASSERT(hasTagName(attachmentTag));
60 }
61
62 HTMLAttachmentElement::~HTMLAttachmentElement() = default;
63
64 Ref<HTMLAttachmentElement> HTMLAttachmentElement::create(const QualifiedName& tagName, Document& document)
65 {
66     return adoptRef(*new HTMLAttachmentElement(tagName, document));
67 }
68
69 RenderPtr<RenderElement> HTMLAttachmentElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
70 {
71     return createRenderer<RenderAttachment>(*this, WTFMove(style));
72 }
73
74 const String& HTMLAttachmentElement::getAttachmentIdentifier(HTMLImageElement& image)
75 {
76     if (auto attachment = image.attachmentElement())
77         return attachment->uniqueIdentifier();
78
79     auto& document = image.document();
80     auto attachment = create(HTMLNames::attachmentTag, document);
81     auto& identifier = attachment->ensureUniqueIdentifier();
82
83     document.registerAttachmentIdentifier(identifier);
84     image.setAttachmentElement(WTFMove(attachment));
85
86     return identifier;
87 }
88
89 URL HTMLAttachmentElement::archiveResourceURL(const String& identifier)
90 {
91     auto resourceURL = URL({ }, "applewebdata://attachment/"_s);
92     resourceURL.setPath(identifier);
93     return resourceURL;
94 }
95
96 File* HTMLAttachmentElement::file() const
97 {
98     return m_file.get();
99 }
100
101 URL HTMLAttachmentElement::blobURL() const
102 {
103     return { { }, attributeWithoutSynchronization(HTMLNames::webkitattachmentbloburlAttr).string() };
104 }
105
106 void HTMLAttachmentElement::setFile(RefPtr<File>&& file, UpdateDisplayAttributes updateAttributes)
107 {
108     m_file = WTFMove(file);
109
110     if (updateAttributes == UpdateDisplayAttributes::Yes) {
111         if (m_file) {
112             setAttributeWithoutSynchronization(HTMLNames::titleAttr, m_file->name());
113             setAttributeWithoutSynchronization(HTMLNames::subtitleAttr, fileSizeDescription(m_file->size()));
114             setAttributeWithoutSynchronization(HTMLNames::typeAttr, m_file->type());
115         } else {
116             removeAttribute(HTMLNames::titleAttr);
117             removeAttribute(HTMLNames::subtitleAttr);
118             removeAttribute(HTMLNames::typeAttr);
119         }
120     }
121
122     if (auto* renderer = this->renderer())
123         renderer->invalidate();
124 }
125
126 Node::InsertedIntoAncestorResult HTMLAttachmentElement::insertedIntoAncestor(InsertionType type, ContainerNode& ancestor)
127 {
128     auto result = HTMLElement::insertedIntoAncestor(type, ancestor);
129     if (type.connectedToDocument)
130         document().didInsertAttachmentElement(*this);
131     return result;
132 }
133
134 void HTMLAttachmentElement::removedFromAncestor(RemovalType type, ContainerNode& ancestor)
135 {
136     HTMLElement::removedFromAncestor(type, ancestor);
137     if (type.disconnectedFromDocument)
138         document().didRemoveAttachmentElement(*this);
139 }
140
141 const String& HTMLAttachmentElement::ensureUniqueIdentifier()
142 {
143     if (m_uniqueIdentifier.isEmpty())
144         m_uniqueIdentifier = createCanonicalUUIDString();
145     return m_uniqueIdentifier;
146 }
147
148 bool HTMLAttachmentElement::hasEnclosingImage() const
149 {
150     return is<HTMLImageElement>(shadowHost());
151 }
152
153 void HTMLAttachmentElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
154 {
155     if (name == progressAttr || name == subtitleAttr || name == titleAttr || name == typeAttr) {
156         if (auto* renderer = this->renderer())
157             renderer->invalidate();
158     }
159
160     HTMLElement::parseAttribute(name, value);
161 }
162
163 String HTMLAttachmentElement::attachmentTitle() const
164 {
165     auto& title = attributeWithoutSynchronization(titleAttr);
166     if (!title.isEmpty())
167         return title;
168     return m_file ? m_file->name() : String();
169 }
170
171 String HTMLAttachmentElement::attachmentTitleForDisplay() const
172 {
173     auto title = attachmentTitle();
174
175     auto indexOfLastDot = title.reverseFind('.');
176     if (indexOfLastDot == notFound)
177         return title;
178
179     String name = title.left(indexOfLastDot);
180     String extension = title.substring(indexOfLastDot);
181
182     StringBuilder builder;
183     builder.append(leftToRightMark);
184     builder.append(firstStrongIsolate);
185     builder.append(name);
186     builder.append(popDirectionalIsolate);
187     builder.append(extension);
188
189     return builder.toString();
190 }
191
192 String HTMLAttachmentElement::attachmentType() const
193 {
194     return attributeWithoutSynchronization(typeAttr);
195 }
196
197 String HTMLAttachmentElement::attachmentPath() const
198 {
199     return attributeWithoutSynchronization(webkitattachmentpathAttr);
200 }
201
202 void HTMLAttachmentElement::updateAttributes(std::optional<uint64_t>&& newFileSize, const String& newContentType, const String& newFilename)
203 {
204     if (!newFilename.isNull())
205         setAttributeWithoutSynchronization(HTMLNames::titleAttr, newFilename);
206     else
207         removeAttribute(HTMLNames::titleAttr);
208
209     if (!newContentType.isNull())
210         setAttributeWithoutSynchronization(HTMLNames::typeAttr, newContentType);
211     else
212         removeAttribute(HTMLNames::typeAttr);
213
214     if (newFileSize)
215         setAttributeWithoutSynchronization(HTMLNames::subtitleAttr, fileSizeDescription(*newFileSize));
216     else
217         removeAttribute(HTMLNames::subtitleAttr);
218
219     if (auto* renderer = this->renderer())
220         renderer->invalidate();
221 }
222
223 void HTMLAttachmentElement::updateEnclosingImageWithData(const String& contentType, Ref<SharedBuffer>&& data)
224 {
225     auto* hostElement = shadowHost();
226     if (!is<HTMLImageElement>(hostElement) || !data->size())
227         return;
228
229     String mimeType = contentType;
230 #if PLATFORM(COCOA)
231     if (isDeclaredUTI(contentType))
232         mimeType = MIMETypeFromUTI(contentType);
233 #endif
234
235     if (!MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
236         return;
237
238     hostElement->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document(), Blob::create(WTFMove(data), mimeType)));
239 }
240
241 } // namespace WebCore
242
243 #endif // ENABLE(ATTACHMENT_ELEMENT)