1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 * 21 * Portions are Copyright (C) 2002 Netscape Communications Corporation. 22 * Other contributors: David Baron <dbaron (at) fas.harvard.edu> 23 * 24 * This library is free software; you can redistribute it and/or 25 * modify it under the terms of the GNU Lesser General Public 26 * License as published by the Free Software Foundation; either 27 * version 2.1 of the License, or (at your option) any later version. 28 * 29 * This library is distributed in the hope that it will be useful, 30 * but WITHOUT ANY WARRANTY; without even the implied warranty of 31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 32 * Lesser General Public License for more details. 33 * 34 * You should have received a copy of the GNU Lesser General Public 35 * License along with this library; if not, write to the Free Software 36 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 37 * 38 * Alternatively, the document type parsing portions of this file may be used 39 * under the terms of either the Mozilla Public License Version 1.1, found at 40 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public 41 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html 42 * (the "GPL"), in which case the provisions of the MPL or the GPL are 43 * applicable instead of those above. If you wish to allow use of your 44 * version of this file only under the terms of one of those two 45 * licenses (the MPL or the GPL) and not to allow others to use your 46 * version of this file under the LGPL, indicate your decision by 47 * deleting the provisions above and replace them with the notice and 48 * other provisions required by the MPL or the GPL, as the case may be. 49 * If you do not delete the provisions above, a recipient may use your 50 * version of this file under any of the LGPL, the MPL or the GPL. 51 */ 52 53 #include "config.h" 54 #include "core/html/HTMLDocument.h" 55 56 #include "HTMLNames.h" 57 #include "bindings/v8/ScriptController.h" 58 #include "core/frame/DOMWindow.h" 59 #include "core/frame/Frame.h" 60 #include "core/frame/FrameView.h" 61 #include "core/html/HTMLBodyElement.h" 62 #include "core/page/FocusController.h" 63 #include "core/page/FrameTree.h" 64 #include "core/page/Page.h" 65 #include "wtf/text/StringBuilder.h" 66 67 namespace WebCore { 68 69 using namespace HTMLNames; 70 71 HTMLDocument::HTMLDocument(const DocumentInit& initializer, DocumentClassFlags extendedDocumentClasses) 72 : Document(initializer, HTMLDocumentClass | extendedDocumentClasses) 73 { 74 ScriptWrappable::init(this); 75 clearXMLVersion(); 76 } 77 78 HTMLDocument::~HTMLDocument() 79 { 80 } 81 82 const AtomicString& HTMLDocument::dir() 83 { 84 HTMLElement* b = body(); 85 if (!b) 86 return nullAtom; 87 return b->getAttribute(dirAttr); 88 } 89 90 void HTMLDocument::setDir(const AtomicString& value) 91 { 92 HTMLElement* b = body(); 93 if (b) 94 b->setAttribute(dirAttr, value); 95 } 96 97 String HTMLDocument::designMode() const 98 { 99 return inDesignMode() ? "on" : "off"; 100 } 101 102 void HTMLDocument::setDesignMode(const String& value) 103 { 104 InheritedBool mode; 105 if (equalIgnoringCase(value, "on")) 106 mode = on; 107 else if (equalIgnoringCase(value, "off")) 108 mode = off; 109 else 110 mode = inherit; 111 Document::setDesignMode(mode); 112 } 113 114 Element* HTMLDocument::activeElement() 115 { 116 if (Element* element = treeScope().adjustedFocusedElement()) 117 return element; 118 return body(); 119 } 120 121 bool HTMLDocument::hasFocus() 122 { 123 Page* page = this->page(); 124 if (!page) 125 return false; 126 if (!page->focusController().isActive() || !page->focusController().isFocused()) 127 return false; 128 if (Frame* focusedFrame = page->focusController().focusedFrame()) { 129 if (focusedFrame->tree().isDescendantOf(frame())) 130 return true; 131 } 132 return false; 133 } 134 135 HTMLBodyElement* HTMLDocument::htmlBodyElement() const 136 { 137 HTMLElement* body = this->body(); 138 return (body && body->hasTagName(bodyTag)) ? toHTMLBodyElement(body) : 0; 139 } 140 141 const AtomicString& HTMLDocument::bodyAttributeValue(const QualifiedName& name) const 142 { 143 if (HTMLBodyElement* body = htmlBodyElement()) 144 return body->fastGetAttribute(name); 145 return nullAtom; 146 } 147 148 void HTMLDocument::setBodyAttribute(const QualifiedName& name, const AtomicString& value) 149 { 150 if (HTMLBodyElement* body = htmlBodyElement()) { 151 // FIXME: This check is apparently for benchmarks that set the same value repeatedly. 152 // It's not clear what benchmarks though, it's also not clear why we don't avoid 153 // causing a style recalc when setting the same value to a presentational attribute 154 // in the common case. 155 if (body->fastGetAttribute(name) != value) 156 body->setAttribute(name, value); 157 } 158 } 159 160 const AtomicString& HTMLDocument::bgColor() const 161 { 162 return bodyAttributeValue(bgcolorAttr); 163 } 164 165 void HTMLDocument::setBgColor(const AtomicString& value) 166 { 167 setBodyAttribute(bgcolorAttr, value); 168 } 169 170 const AtomicString& HTMLDocument::fgColor() const 171 { 172 return bodyAttributeValue(textAttr); 173 } 174 175 void HTMLDocument::setFgColor(const AtomicString& value) 176 { 177 setBodyAttribute(textAttr, value); 178 } 179 180 const AtomicString& HTMLDocument::alinkColor() const 181 { 182 return bodyAttributeValue(alinkAttr); 183 } 184 185 void HTMLDocument::setAlinkColor(const AtomicString& value) 186 { 187 setBodyAttribute(alinkAttr, value); 188 } 189 190 const AtomicString& HTMLDocument::linkColor() const 191 { 192 return bodyAttributeValue(linkAttr); 193 } 194 195 void HTMLDocument::setLinkColor(const AtomicString& value) 196 { 197 setBodyAttribute(linkAttr, value); 198 } 199 200 const AtomicString& HTMLDocument::vlinkColor() const 201 { 202 return bodyAttributeValue(vlinkAttr); 203 } 204 205 void HTMLDocument::setVlinkColor(const AtomicString& value) 206 { 207 setBodyAttribute(vlinkAttr, value); 208 } 209 210 PassRefPtr<Document> HTMLDocument::cloneDocumentWithoutChildren() 211 { 212 return create(DocumentInit(url()).withRegistrationContext(registrationContext())); 213 } 214 215 // -------------------------------------------------------------------------- 216 // not part of the DOM 217 // -------------------------------------------------------------------------- 218 219 void HTMLDocument::addItemToMap(HashCountedSet<AtomicString>& map, const AtomicString& name) 220 { 221 if (name.isEmpty()) 222 return; 223 map.add(name); 224 if (Frame* f = frame()) 225 f->script().namedItemAdded(this, name); 226 } 227 228 void HTMLDocument::removeItemFromMap(HashCountedSet<AtomicString>& map, const AtomicString& name) 229 { 230 if (name.isEmpty()) 231 return; 232 map.remove(name); 233 if (Frame* f = frame()) 234 f->script().namedItemRemoved(this, name); 235 } 236 237 void HTMLDocument::addNamedItem(const AtomicString& name) 238 { 239 addItemToMap(m_namedItemCounts, name); 240 } 241 242 void HTMLDocument::removeNamedItem(const AtomicString& name) 243 { 244 removeItemFromMap(m_namedItemCounts, name); 245 } 246 247 void HTMLDocument::addExtraNamedItem(const AtomicString& name) 248 { 249 addItemToMap(m_extraNamedItemCounts, name); 250 } 251 252 void HTMLDocument::removeExtraNamedItem(const AtomicString& name) 253 { 254 removeItemFromMap(m_extraNamedItemCounts, name); 255 } 256 257 static void addLocalNameToSet(HashSet<StringImpl*>* set, const QualifiedName& qName) 258 { 259 set->add(qName.localName().impl()); 260 } 261 262 static HashSet<StringImpl*>* createHtmlCaseInsensitiveAttributesSet() 263 { 264 // This is the list of attributes in HTML 4.01 with values marked as "[CI]" or case-insensitive 265 // Mozilla treats all other values as case-sensitive, thus so do we. 266 HashSet<StringImpl*>* attrSet = new HashSet<StringImpl*>; 267 268 addLocalNameToSet(attrSet, accept_charsetAttr); 269 addLocalNameToSet(attrSet, acceptAttr); 270 addLocalNameToSet(attrSet, alignAttr); 271 addLocalNameToSet(attrSet, alinkAttr); 272 addLocalNameToSet(attrSet, axisAttr); 273 addLocalNameToSet(attrSet, bgcolorAttr); 274 addLocalNameToSet(attrSet, charsetAttr); 275 addLocalNameToSet(attrSet, checkedAttr); 276 addLocalNameToSet(attrSet, clearAttr); 277 addLocalNameToSet(attrSet, codetypeAttr); 278 addLocalNameToSet(attrSet, colorAttr); 279 addLocalNameToSet(attrSet, compactAttr); 280 addLocalNameToSet(attrSet, declareAttr); 281 addLocalNameToSet(attrSet, deferAttr); 282 addLocalNameToSet(attrSet, dirAttr); 283 addLocalNameToSet(attrSet, disabledAttr); 284 addLocalNameToSet(attrSet, enctypeAttr); 285 addLocalNameToSet(attrSet, faceAttr); 286 addLocalNameToSet(attrSet, frameAttr); 287 addLocalNameToSet(attrSet, hreflangAttr); 288 addLocalNameToSet(attrSet, http_equivAttr); 289 addLocalNameToSet(attrSet, langAttr); 290 addLocalNameToSet(attrSet, languageAttr); 291 addLocalNameToSet(attrSet, linkAttr); 292 addLocalNameToSet(attrSet, mediaAttr); 293 addLocalNameToSet(attrSet, methodAttr); 294 addLocalNameToSet(attrSet, multipleAttr); 295 addLocalNameToSet(attrSet, nohrefAttr); 296 addLocalNameToSet(attrSet, noresizeAttr); 297 addLocalNameToSet(attrSet, noshadeAttr); 298 addLocalNameToSet(attrSet, nowrapAttr); 299 addLocalNameToSet(attrSet, readonlyAttr); 300 addLocalNameToSet(attrSet, relAttr); 301 addLocalNameToSet(attrSet, revAttr); 302 addLocalNameToSet(attrSet, rulesAttr); 303 addLocalNameToSet(attrSet, scopeAttr); 304 addLocalNameToSet(attrSet, scrollingAttr); 305 addLocalNameToSet(attrSet, selectedAttr); 306 addLocalNameToSet(attrSet, shapeAttr); 307 addLocalNameToSet(attrSet, targetAttr); 308 addLocalNameToSet(attrSet, textAttr); 309 addLocalNameToSet(attrSet, typeAttr); 310 addLocalNameToSet(attrSet, valignAttr); 311 addLocalNameToSet(attrSet, valuetypeAttr); 312 addLocalNameToSet(attrSet, vlinkAttr); 313 314 return attrSet; 315 } 316 317 bool HTMLDocument::isCaseSensitiveAttribute(const QualifiedName& attributeName) 318 { 319 static HashSet<StringImpl*>* htmlCaseInsensitiveAttributesSet = createHtmlCaseInsensitiveAttributesSet(); 320 bool isPossibleHTMLAttr = !attributeName.hasPrefix() && (attributeName.namespaceURI() == nullAtom); 321 return !isPossibleHTMLAttr || !htmlCaseInsensitiveAttributesSet->contains(attributeName.localName().impl()); 322 } 323 324 void HTMLDocument::clear() 325 { 326 // FIXME: This does nothing, and that seems unlikely to be correct. 327 // We've long had a comment saying that IE doesn't support this. 328 // But I do see it in the documentation for Mozilla. 329 } 330 331 void HTMLDocument::write(DOMWindow* activeWindow, const Vector<String>& text) 332 { 333 ASSERT(activeWindow); 334 StringBuilder builder; 335 for (size_t i = 0; i < text.size(); ++i) 336 builder.append(text[i]); 337 write(builder.toString(), activeWindow->document()); 338 } 339 340 void HTMLDocument::writeln(DOMWindow* activeWindow, const Vector<String>& text) 341 { 342 ASSERT(activeWindow); 343 StringBuilder builder; 344 for (size_t i = 0; i < text.size(); ++i) 345 builder.append(text[i]); 346 writeln(builder.toString(), activeWindow->document()); 347 } 348 349 } 350