blob: 524d24ac0a2575e3018142d5f39dfaf1a33c707a [file] [log] [blame]
darin@apple.com815d7b52009-01-05 18:24:12 +00001/*
darinb9481ed2006-03-20 02:57:59 +00002 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
ap0289d282006-11-20 18:59:12 +00005 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
antti@apple.comda4d9c512012-04-11 23:20:55 +00006 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
staikos@webkit.org159f11f2009-05-18 23:48:30 +00007 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00008 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +00009 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
commit-queue@webkit.org160529f2011-12-07 23:41:21 +000010 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
darinb9481ed2006-03-20 02:57:59 +000011 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public License
23 * along with this library; see the file COPYING.LIB. If not, write to
ddkilzerc8eccec2007-09-26 02:29:57 +000024 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
darinb9481ed2006-03-20 02:57:59 +000026 */
27
28#include "config.h"
29#include "Document.h"
30
darine775cf72006-07-09 22:48:56 +000031#include "AXObjectCache.h"
weinig@apple.com5af461c2009-04-08 22:16:23 +000032#include "AnimationController.h"
darin@apple.com9a925fa2009-05-04 18:00:34 +000033#include "Attr.h"
weinig@apple.comc3608932010-05-19 17:48:06 +000034#include "Attribute.h"
darinb9481ed2006-03-20 02:57:59 +000035#include "CDATASection.h"
mihnea@adobe.comcda097f2012-03-05 23:31:50 +000036#include "CSSParser.h"
jamesr@google.com2b9efdf2012-02-21 21:35:38 +000037#include "CSSStyleDeclaration.h"
eseidelb3f42132006-05-16 02:08:51 +000038#include "CSSStyleSheet.h"
darin36d11362006-04-11 16:30:21 +000039#include "CSSValueKeywords.h"
weinig@apple.comba6e6652008-05-09 20:52:15 +000040#include "CachedCSSStyleSheet.h"
tonyg@chromium.org987a93b2011-01-04 16:56:17 +000041#include "CachedResourceLoader.h"
aroben@apple.coma7c639a2009-12-18 17:38:45 +000042#include "Chrome.h"
eric@webkit.orga1d89652010-01-21 03:49:51 +000043#include "ChromeClient.h"
darinb9481ed2006-03-20 02:57:59 +000044#include "Comment.h"
ap@webkit.orge9b6b592008-11-19 17:42:39 +000045#include "Console.h"
abarth@webkit.orgf921dee2011-03-26 11:59:34 +000046#include "ContentSecurityPolicy.h"
morrita@google.comac743042012-06-13 08:05:43 +000047#include "ContextFeatures.h"
oliver9119a9c2007-10-12 15:13:16 +000048#include "CookieJar.h"
darinb9481ed2006-03-20 02:57:59 +000049#include "DOMImplementation.h"
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +000050#include "DOMNamedFlowCollection.h"
shinyak@chromium.org4fd60ed2012-05-11 10:36:31 +000051#include "DOMSelection.h"
weinig@apple.comba6e6652008-05-09 20:52:15 +000052#include "DOMWindow.h"
weinig@apple.com1a8cc9d2011-09-04 21:04:14 +000053#include "DateComponents.h"
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +000054#include "DeviceMotionController.h"
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +000055#include "DeviceOrientationController.h"
dgrogan@chromium.org65c22c82011-10-27 23:15:04 +000056#include "DocumentEventQueue.h"
darinb9481ed2006-03-20 02:57:59 +000057#include "DocumentFragment.h"
darinc370e7e2006-11-08 05:52:27 +000058#include "DocumentLoader.h"
tonyg@chromium.org987a93b2011-01-04 16:56:17 +000059#include "DocumentMarkerController.h"
antti@apple.come5a88a72012-09-24 22:14:47 +000060#include "DocumentStyleSheetCollection.h"
darinb9481ed2006-03-20 02:57:59 +000061#include "DocumentType.h"
62#include "EditingText.h"
anderscaf2ad1b52006-11-09 00:51:35 +000063#include "Editor.h"
aestes@apple.com62683822011-02-11 07:21:54 +000064#include "Element.h"
morrita@google.com948bd532012-05-07 06:05:42 +000065#include "ElementShadow.h"
eseidel6e4fe452006-05-15 23:53:33 +000066#include "EntityReference.h"
weinig681a5172006-06-19 22:58:36 +000067#include "Event.h"
abarth@webkit.org08feba42011-10-20 04:50:14 +000068#include "EventFactory.h"
darin60e537f52006-11-15 01:29:46 +000069#include "EventHandler.h"
darin817909f2006-04-17 05:34:58 +000070#include "EventListener.h"
darinb9481ed2006-03-20 02:57:59 +000071#include "EventNames.h"
72#include "ExceptionCode.h"
mihnea@adobe.comd030fcd2012-04-11 09:41:37 +000073#include "FlowThreadController.h"
ggaren7c5851a2006-12-12 22:11:18 +000074#include "FocusController.h"
tkent@chromium.org34554872012-06-08 09:53:52 +000075#include "FormController.h"
darinb9481ed2006-03-20 02:57:59 +000076#include "Frame.h"
ggarenb2497d82006-10-28 01:22:13 +000077#include "FrameLoader.h"
ap@apple.com43af8a82010-10-29 17:23:55 +000078#include "FrameLoaderClient.h"
rniwa@webkit.org78bbc942011-05-05 18:14:43 +000079#include "FrameSelection.h"
darinb9481ed2006-03-20 02:57:59 +000080#include "FrameTree.h"
darin647be152006-11-05 22:02:23 +000081#include "FrameView.h"
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +000082#include "GeolocationController.h"
abarth@webkit.org08feba42011-10-20 04:50:14 +000083#include "HashChangeEvent.h"
commit-queue@webkit.orgbfdd4722011-12-17 00:58:33 +000084#include "HistogramSupport.h"
commit-queue@webkit.org7a2b40f2012-02-23 03:05:55 +000085#include "History.h"
weinig@apple.com963305c2009-10-23 21:12:03 +000086#include "HTMLAllCollection.h"
darin@apple.com72b7bb52009-01-05 17:32:03 +000087#include "HTMLAnchorElement.h"
eseidel409f4302006-05-12 22:56:41 +000088#include "HTMLBodyElement.h"
hyatt@apple.com68382152008-04-17 04:13:36 +000089#include "HTMLCanvasElement.h"
darin@apple.com9a925fa2009-05-04 18:00:34 +000090#include "HTMLCollection.h"
darin36d11362006-04-11 16:30:21 +000091#include "HTMLDocument.h"
92#include "HTMLElementFactory.h"
darincb3524a2006-12-11 23:40:47 +000093#include "HTMLFrameOwnerElement.h"
darina6a0caf2007-01-25 00:16:44 +000094#include "HTMLHeadElement.h"
dimich@chromium.org451eabb2010-01-27 00:22:37 +000095#include "HTMLIFrameElement.h"
eseidel1bdb6f52006-05-12 20:44:25 +000096#include "HTMLLinkElement.h"
eseidel84943622006-05-15 23:23:42 +000097#include "HTMLMapElement.h"
darinb9481ed2006-03-20 02:57:59 +000098#include "HTMLNameCollection.h"
darin36d11362006-04-11 16:30:21 +000099#include "HTMLNames.h"
darin@apple.com7b7981b2010-10-01 00:04:02 +0000100#include "HTMLParserIdioms.h"
eseidel1bdb6f52006-05-12 20:44:25 +0000101#include "HTMLStyleElement.h"
bdashf45c4e32007-01-24 03:44:47 +0000102#include "HTMLTitleElement.h"
ape9991d52006-12-08 18:19:51 +0000103#include "HTTPParsers.h"
weinige7918082007-07-18 19:56:40 +0000104#include "HitTestRequest.h"
105#include "HitTestResult.h"
zimmermann@webkit.org953b7442008-09-20 20:19:45 +0000106#include "ImageLoader.h"
yurys@chromium.org793b08e2012-02-17 08:33:30 +0000107#include "InspectorCounters.h"
commit-queue@webkit.org4c49a662011-01-02 22:27:10 +0000108#include "InspectorInstrumentation.h"
tkent@chromium.orgaff3c932012-09-14 12:40:27 +0000109#include "Language.h"
110#include "Localizer.h"
darinb9481ed2006-03-20 02:57:59 +0000111#include "Logging.h"
loislo@chromium.orgc10e0982012-09-26 14:10:50 +0000112#include "MediaCanStartListener.h"
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +0000113#include "MediaQueryList.h"
114#include "MediaQueryMatcher.h"
darinb9481ed2006-03-20 02:57:59 +0000115#include "MouseEventWithHitTestResults.h"
116#include "NameNodeList.h"
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +0000117#include "NamedFlowCollection.h"
commit-queue@webkit.orgb7b2b522011-02-02 00:22:52 +0000118#include "NestingLevelIncrementer.h"
jpfau@apple.come854e5d2011-07-08 19:31:34 +0000119#include "NewXMLDocumentParser.h"
darinb4483822006-06-02 06:30:49 +0000120#include "NodeFilter.h"
121#include "NodeIterator.h"
rniwa@webkit.orgfdcdadf2012-06-14 22:38:41 +0000122#include "NodeRareData.h"
darin@apple.comf28fa1b2008-03-15 17:26:28 +0000123#include "NodeWithIndex.h"
oliverf8f07792007-05-11 21:54:12 +0000124#include "Page.h"
hyatt@apple.com63e0ac22009-09-09 21:12:10 +0000125#include "PageGroup.h"
ap@apple.com383dde52009-08-27 17:46:39 +0000126#include "PageTransitionEvent.h"
darin36d11362006-04-11 16:30:21 +0000127#include "PlatformKeyboardEvent.h"
jpu@apple.comdfd2ce62012-04-16 03:05:06 +0000128#include "PluginDocument.h"
scheib@chromium.org6ed01762012-06-12 03:02:16 +0000129#include "PointerLockController.h"
beidson@apple.com08c61752009-12-03 19:04:40 +0000130#include "PopStateEvent.h"
eseidel6e4fe452006-05-15 23:53:33 +0000131#include "ProcessingInstruction.h"
kling@webkit.orgca1e2d42012-09-24 00:57:54 +0000132#include "QualifiedName.h"
weinig681a5172006-06-19 22:58:36 +0000133#include "RegisteredEventListener.h"
darin36d11362006-04-11 16:30:21 +0000134#include "RenderArena.h"
hyatt@apple.com04cdbe42012-03-28 22:15:31 +0000135#include "RenderNamedFlowThread.h"
hyatt@apple.come6dedc02009-02-13 19:18:36 +0000136#include "RenderTextControl.h"
hyattd8048342006-05-31 01:48:18 +0000137#include "RenderView.h"
eseidel409f4302006-05-12 22:56:41 +0000138#include "RenderWidget.h"
tkent@chromium.orgaff3c932012-09-14 12:40:27 +0000139#include "RuntimeEnabledFeatures.h"
jberlin@webkit.orgda2af492011-11-07 18:16:33 +0000140#include "SchemeRegistry.h"
abarth@webkit.org90a3ca62011-04-14 19:54:30 +0000141#include "ScopedEventQueue.h"
yurys@chromium.orgc8a06eb2011-01-20 09:28:54 +0000142#include "ScriptCallStack.h"
abarth@webkit.org24d63ef2008-12-10 06:48:36 +0000143#include "ScriptController.h"
mitz@apple.com73169a12009-04-20 04:20:08 +0000144#include "ScriptElement.h"
darin@apple.com3a3edd42009-08-19 00:17:59 +0000145#include "ScriptEventListener.h"
simonjam@chromium.org5871a052011-03-16 00:00:09 +0000146#include "ScriptRunner.h"
jamesr@google.com0abe0062012-02-18 00:23:16 +0000147#include "ScrollingCoordinator.h"
weinige06430a2007-10-19 20:53:22 +0000148#include "SecurityOrigin.h"
abarth@webkit.orgeea90662011-11-09 07:58:49 +0000149#include "SecurityPolicy.h"
darinb9481ed2006-03-20 02:57:59 +0000150#include "SegmentedString.h"
haraken@chromium.org3981f522012-06-02 19:23:25 +0000151#include "SelectorQuery.h"
ggaren6ad6e762007-05-25 09:13:32 +0000152#include "Settings.h"
rolandsteiner@chromium.org6d944b82011-04-21 17:44:14 +0000153#include "ShadowRoot.h"
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +0000154#include "StaticHashSetNodeList.h"
alexis.menard@openbossa.orge6db2f62012-04-25 15:49:08 +0000155#include "StyleResolver.h"
antti@apple.com069713a2012-05-24 08:54:22 +0000156#include "StyleSheetContents.h"
eseidelb3f42132006-05-16 02:08:51 +0000157#include "StyleSheetList.h"
darinc370e7e2006-11-08 05:52:27 +0000158#include "TextResourceDecoder.h"
ap@webkit.orga3f2d9f2008-12-04 07:20:45 +0000159#include "Timer.h"
hausmann@webkit.org06b7e552009-09-28 20:11:36 +0000160#include "TransformSource.h"
weinig@apple.com5af461c2009-04-08 22:16:23 +0000161#include "TreeWalker.h"
commit-queue@webkit.org5deb7492012-06-09 09:05:22 +0000162#include "UndoManager.h"
hyatt@apple.com5d1c0e72009-09-30 00:32:38 +0000163#include "UserContentURLPattern.h"
loislo@chromium.orgc4389122012-09-07 15:36:43 +0000164#include "WebCoreMemoryInstrumentation.h"
mihnea@adobe.com88a6cdd2011-12-08 14:23:10 +0000165#include "WebKitNamedFlow.h"
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000166#include "XMLDocumentParser.h"
weinig62f94be2007-07-18 20:37:20 +0000167#include "XMLHttpRequest.h"
ap@apple.com38221c62010-01-18 22:05:55 +0000168#include "XMLNSNames.h"
eric@webkit.org4e5ae832008-03-22 09:49:58 +0000169#include "XMLNames.h"
abarth@webkit.org32638ce2011-10-18 17:21:28 +0000170#include "XPathEvaluator.h"
171#include "XPathExpression.h"
172#include "XPathNSResolver.h"
173#include "XPathResult.h"
weinig@apple.com628cb2c2009-09-08 22:02:41 +0000174#include "htmlediting.h"
ap@webkit.orgc01ff492009-01-11 08:14:58 +0000175#include <wtf/CurrentTime.h>
dsmith@webkit.org69601f92009-01-03 00:25:59 +0000176#include <wtf/HashFunctions.h>
ap@webkit.orga3f2d9f2008-12-04 07:20:45 +0000177#include <wtf/MainThread.h>
yurys@chromium.org9c990162012-10-01 14:46:25 +0000178#include <wtf/MemoryInstrumentationHashMap.h>
loislo@chromium.orgc10e0982012-09-26 14:10:50 +0000179#include <wtf/MemoryInstrumentationHashSet.h>
loislo@chromium.org83736932012-09-25 07:54:44 +0000180#include <wtf/MemoryInstrumentationVector.h>
ap@webkit.orga3f2d9f2008-12-04 07:20:45 +0000181#include <wtf/PassRefPtr.h>
weinig@apple.com5af461c2009-04-08 22:16:23 +0000182#include <wtf/StdLibExtras.h>
barraclough@apple.combbb3cd42010-08-10 17:45:41 +0000183#include <wtf/text/StringBuffer.h>
darinb4483822006-06-02 06:30:49 +0000184
weinig@apple.com628cb2c2009-09-08 22:02:41 +0000185#if ENABLE(SHARED_WORKERS)
186#include "SharedWorkerRepository.h"
187#endif
188
mjsd2948ef2007-02-26 19:29:04 +0000189#if ENABLE(XSLT)
darinb9481ed2006-03-20 02:57:59 +0000190#include "XSLTProcessor.h"
191#endif
192
mjsd2948ef2007-02-26 19:29:04 +0000193#if ENABLE(SVG)
darinb9481ed2006-03-20 02:57:59 +0000194#include "SVGDocumentExtensions.h"
195#include "SVGElementFactory.h"
krit@webkit.org5e3479c2009-08-24 06:00:03 +0000196#include "SVGNames.h"
zimmermann@webkit.org3d2114c2012-02-08 10:21:49 +0000197#include "SVGSVGElement.h"
darinb9481ed2006-03-20 02:57:59 +0000198#include "SVGStyleElement.h"
darinb9481ed2006-03-20 02:57:59 +0000199#endif
200
eric@webkit.orge0e14202010-01-14 10:03:34 +0000201#if ENABLE(TOUCH_EVENTS)
tonyg@chromium.org8d183cb2011-05-10 08:19:52 +0000202#include "TouchList.h"
eric@webkit.orge0e14202010-01-14 10:03:34 +0000203#endif
204
eric@webkit.org8af95f32009-09-19 18:02:33 +0000205#if ENABLE(MATHML)
206#include "MathMLElement.h"
207#include "MathMLElementFactory.h"
208#include "MathMLNames.h"
209#endif
210
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +0000211#if ENABLE(FULLSCREEN_API)
212#include "RenderFullScreen.h"
213#endif
214
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +0000215#if ENABLE(REQUEST_ANIMATION_FRAME)
216#include "RequestAnimationFrameCallback.h"
jamesr@google.com9f8b52b2011-02-16 00:53:36 +0000217#include "ScriptedAnimationController.h"
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +0000218#endif
219
rniwa@webkit.org43f105f2011-10-14 16:13:01 +0000220#if ENABLE(MICRODATA)
221#include "MicroDataItemList.h"
222#include "NodeRareData.h"
223#endif
224
gavinp@chromium.orgaf445b92012-05-15 04:42:52 +0000225#if ENABLE(LINK_PRERENDER)
226#include "Prerenderer.h"
227#endif
228
commit-queue@webkit.org85cce8f2012-07-04 17:43:12 +0000229#if ENABLE(TEXT_AUTOSIZING)
230#include "TextAutosizer.h"
231#endif
232
commit-queue@webkit.org05199e52012-07-26 09:49:52 +0000233#if ENABLE(CSP_NEXT)
234#include "DOMSecurityPolicy.h"
235#endif
236
darin7bd70952006-04-13 07:07:34 +0000237using namespace std;
darinf9e5d6c2007-01-09 14:54:26 +0000238using namespace WTF;
239using namespace Unicode;
darin7bd70952006-04-13 07:07:34 +0000240
darinb9481ed2006-03-20 02:57:59 +0000241namespace WebCore {
242
darinb9481ed2006-03-20 02:57:59 +0000243using namespace HTMLNames;
244
245// #define INSTRUMENT_LAYOUT_SCHEDULING 1
246
commit-queue@webkit.orgb7b2b522011-02-02 00:22:52 +0000247static const unsigned cMaxWriteRecursionDepth = 21;
248
darinb9481ed2006-03-20 02:57:59 +0000249// This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
250// FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
251// for dual G5s. :)
darinf9e5d6c2007-01-09 14:54:26 +0000252static const int cLayoutScheduleThreshold = 250;
darinb9481ed2006-03-20 02:57:59 +0000253
darinb9481ed2006-03-20 02:57:59 +0000254// DOM Level 2 says (letters added):
255//
256// a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
257// b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
258// c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
259// d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed.
260// e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6.
261// f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
262// g) Character #x00B7 is classified as an extender, because the property list so identifies it.
263// h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
264// i) Characters ':' and '_' are allowed as name-start characters.
265// j) Characters '-' and '.' are allowed as name characters.
266//
267// It also contains complete tables. If we decide it's better, we could include those instead of the following code.
268
269static inline bool isValidNameStart(UChar32 c)
270{
271 // rule (e) above
272 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
273 return true;
274
275 // rule (i) above
276 if (c == ':' || c == '_')
277 return true;
278
279 // rules (a) and (f) above
darinf9e5d6c2007-01-09 14:54:26 +0000280 const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
281 if (!(Unicode::category(c) & nameStartMask))
darinb9481ed2006-03-20 02:57:59 +0000282 return false;
283
284 // rule (c) above
285 if (c >= 0xF900 && c < 0xFFFE)
286 return false;
287
288 // rule (d) above
darinf9e5d6c2007-01-09 14:54:26 +0000289 DecompositionType decompType = decompositionType(c);
290 if (decompType == DecompositionFont || decompType == DecompositionCompat)
darinb9481ed2006-03-20 02:57:59 +0000291 return false;
292
293 return true;
294}
295
296static inline bool isValidNamePart(UChar32 c)
297{
298 // rules (a), (e), and (i) above
299 if (isValidNameStart(c))
300 return true;
301
302 // rules (g) and (h) above
303 if (c == 0x00B7 || c == 0x0387)
304 return true;
305
306 // rule (j) above
307 if (c == '-' || c == '.')
308 return true;
309
310 // rules (b) and (f) above
darinf9e5d6c2007-01-09 14:54:26 +0000311 const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
312 if (!(Unicode::category(c) & otherNamePartMask))
darinb9481ed2006-03-20 02:57:59 +0000313 return false;
314
315 // rule (c) above
316 if (c >= 0xF900 && c < 0xFFFE)
317 return false;
318
319 // rule (d) above
darinf9e5d6c2007-01-09 14:54:26 +0000320 DecompositionType decompType = decompositionType(c);
321 if (decompType == DecompositionFont || decompType == DecompositionCompat)
darinb9481ed2006-03-20 02:57:59 +0000322 return false;
323
324 return true;
325}
326
abarth@webkit.orgd8cd61a2011-11-14 19:33:02 +0000327static bool shouldInheritSecurityOriginFromOwner(const KURL& url)
328{
329 // http://www.whatwg.org/specs/web-apps/current-work/#origin-0
330 //
331 // If a Document has the address "about:blank"
332 // The origin of the Document is the origin it was assigned when its browsing context was created.
333 //
commit-queue@webkit.orga9b08182012-05-06 22:57:29 +0000334 // Note: We generalize this to all "blank" URLs and invalid URLs because we
abarth@webkit.orgd8cd61a2011-11-14 19:33:02 +0000335 // treat all of these URLs as about:blank.
336 //
commit-queue@webkit.orga9b08182012-05-06 22:57:29 +0000337 return !url.isValid() || url.isBlankURL();
abarth@webkit.orgd8cd61a2011-11-14 19:33:02 +0000338}
339
ggaren03a0f872006-12-15 03:43:51 +0000340static Widget* widgetForNode(Node* focusedNode)
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000341{
ggaren03a0f872006-12-15 03:43:51 +0000342 if (!focusedNode)
343 return 0;
344 RenderObject* renderer = focusedNode->renderer();
345 if (!renderer || !renderer->isWidget())
346 return 0;
darin@apple.com9c962752009-07-30 18:44:42 +0000347 return toRenderWidget(renderer)->widget();
ggaren03a0f872006-12-15 03:43:51 +0000348}
349
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000350static bool acceptsEditingFocus(Node* node)
ggaren03a0f872006-12-15 03:43:51 +0000351{
ggarenf9f32ae2007-03-26 20:08:53 +0000352 ASSERT(node);
commit-queue@webkit.org595681f2011-03-25 16:21:30 +0000353 ASSERT(node->rendererIsEditable());
ggaren03a0f872006-12-15 03:43:51 +0000354
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000355 Node* root = node->rootEditableElement();
ggaren03a0f872006-12-15 03:43:51 +0000356 Frame* frame = node->document()->frame();
357 if (!frame || !root)
358 return false;
359
360 return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
361}
362
abarth@webkit.orga9da3b02012-03-27 01:09:43 +0000363static bool canAccessAncestor(const SecurityOrigin* activeSecurityOrigin, Frame* targetFrame)
364{
365 // targetFrame can be 0 when we're trying to navigate a top-level frame
366 // that has a 0 opener.
367 if (!targetFrame)
368 return false;
369
370 const bool isLocalActiveOrigin = activeSecurityOrigin->isLocal();
371 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
372 Document* ancestorDocument = ancestorFrame->document();
373 // FIXME: Should be an ASSERT? Frames should alway have documents.
374 if (!ancestorDocument)
375 return true;
376
377 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securityOrigin();
378 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin))
379 return true;
380
381 // Allow file URL descendant navigation even when allowFileAccessFromFileURLs is false.
382 // FIXME: It's a bit strange to special-case local origins here. Should we be doing
383 // something more general instead?
384 if (isLocalActiveOrigin && ancestorSecurityOrigin->isLocal())
385 return true;
386 }
387
388 return false;
389}
390
abarth@webkit.org0f97abe2012-04-02 02:43:17 +0000391static void printNavigationErrorMessage(Frame* frame, const KURL& activeURL)
392{
393 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
394 String message = "Unsafe JavaScript attempt to initiate a navigation change for frame with URL " +
395 frame->document()->url().string() + " from frame with URL " + activeURL.string() + ".\n";
396
397 // FIXME: should we print to the console of the document performing the navigation instead?
abarth@webkit.orgb7c61162012-08-14 22:34:01 +0000398 frame->document()->domWindow()->printErrorMessage(message);
abarth@webkit.org0f97abe2012-04-02 02:43:17 +0000399}
400
hyatt@apple.comf6d72f32009-04-10 00:05:02 +0000401static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
darinb9481ed2006-03-20 02:57:59 +0000402
levin@chromium.orge24a9ba2011-03-20 23:30:26 +0000403class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> {
dimich@chromium.orgc252d6d2010-01-20 21:56:08 +0000404public:
405 static PassRefPtr<DocumentWeakReference> create(Document* document)
406 {
407 return adoptRef(new DocumentWeakReference(document));
408 }
409
410 Document* document()
411 {
412 ASSERT(isMainThread());
413 return m_document;
414 }
415
416 void clear()
417 {
418 ASSERT(isMainThread());
419 m_document = 0;
420 }
421
422private:
423 DocumentWeakReference(Document* document)
424 : m_document(document)
425 {
426 ASSERT(isMainThread());
427 }
428
429 Document* m_document;
430};
431
eae@chromium.orga01dd602011-03-11 01:46:48 +0000432uint64_t Document::s_globalTreeVersion = 0;
433
aestes@apple.com10c51ec2011-02-11 06:35:18 +0000434Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
adamk@chromium.org575ab2b2012-03-08 22:47:44 +0000435 : ContainerNode(0, CreateDocument)
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +0000436 , TreeScope(this)
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000437 , m_guardRefCount(0)
morrita@google.comac743042012-06-13 08:05:43 +0000438 , m_contextFeatures(ContextFeatures::defaultSwitch())
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000439 , m_compatibilityMode(NoQuirksMode)
440 , m_compatibilityModeLocked(false)
eae@chromium.orga01dd602011-03-11 01:46:48 +0000441 , m_domTreeVersion(++s_globalTreeVersion)
adamk@chromium.orgf32db172011-11-08 18:29:54 +0000442#if ENABLE(MUTATION_OBSERVERS)
adamk@chromium.orgc3168fb2011-12-16 00:59:39 +0000443 , m_mutationObserverTypes(0)
adamk@chromium.orgf32db172011-11-08 18:29:54 +0000444#endif
antti@apple.come5a88a72012-09-24 22:14:47 +0000445 , m_styleSheetCollection(adoptPtr(new DocumentStyleSheetCollection(this)))
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +0000446 , m_readyState(Complete)
hyatt@apple.comdcf36332009-04-10 03:15:05 +0000447 , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
hyatt@apple.com8dd0d932010-08-26 18:17:59 +0000448 , m_pendingStyleRecalcShouldForce(false)
darin@apple.com160d0002009-01-02 09:27:08 +0000449 , m_frameElementsShouldIgnoreScrolling(false)
adele@apple.comddeabb82010-01-27 01:35:51 +0000450 , m_containsValidityStyleRules(false)
simon.fraser@apple.com9998eac2010-02-05 19:50:24 +0000451 , m_updateFocusAppearanceRestoresSelection(false)
tonyg@chromium.org8500eb82010-10-22 01:27:27 +0000452 , m_ignoreDestructiveWriteCount(0)
darinb9481ed2006-03-20 02:57:59 +0000453 , m_titleSetExplicitly(false)
darin438e6272007-08-16 16:29:48 +0000454 , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
japhet@chromium.org4fdf46f2011-07-06 17:59:59 +0000455 , m_loadEventFinished(false)
eric@webkit.orgef242d82010-01-09 01:25:44 +0000456 , m_startTime(currentTime())
457 , m_overMinimumLayoutThreshold(false)
simonjam@chromium.org5871a052011-03-16 00:00:09 +0000458 , m_scriptRunner(ScriptRunner::create(this))
ap0289d282006-11-20 18:59:12 +0000459 , m_xmlVersion("1.0")
rwlbuis@webkit.orgac5a7ef2012-04-13 00:58:30 +0000460 , m_xmlStandalone(StandaloneUnspecified)
461 , m_hasXMLDeclaration(0)
darinb9481ed2006-03-20 02:57:59 +0000462 , m_savedRenderer(0)
darinb9481ed2006-03-20 02:57:59 +0000463 , m_designMode(inherit)
jianli@chromium.orgf66b5812012-08-02 00:14:28 +0000464#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(WIDGET_REGION)
darinb9481ed2006-03-20 02:57:59 +0000465 , m_hasDashboardRegions(false)
466 , m_dashboardRegionsDirty(false)
ddkilzer@apple.com8fe65862008-04-29 21:31:09 +0000467#endif
darinb9481ed2006-03-20 02:57:59 +0000468 , m_createRenderers(true)
469 , m_inPageCache(false)
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000470 , m_accessKeyMapValid(false)
beidsonc030e972007-05-12 21:22:08 +0000471 , m_useSecureKeyboardEntryWhenActive(false)
mrowe@apple.com46633d32007-12-17 01:26:46 +0000472 , m_isXHTML(isXHTML)
mjs@apple.com12321112010-01-20 02:25:21 +0000473 , m_isHTML(isHTML)
japhet@chromium.org0d6b1de2011-05-25 18:51:27 +0000474 , m_isViewSource(false)
pfeldman@chromium.org81b45e52011-02-28 15:26:44 +0000475 , m_sawElementsInKnownNamespaces(false)
abarth@webkit.orgb2515fa2012-04-04 05:54:26 +0000476 , m_isSrcdocDocument(false)
haraken@chromium.orgabf5d022012-06-28 06:29:27 +0000477 , m_documentRareData(0)
dgrogan@chromium.org65c22c82011-10-27 23:15:04 +0000478 , m_eventQueue(DocumentEventQueue::create(this))
dimich@chromium.org948b9a32010-01-15 21:47:15 +0000479 , m_weakReference(DocumentWeakReference::create(this))
darin@apple.comf5247d12010-06-13 17:29:10 +0000480 , m_idAttributeName(idAttr)
jer.noble@apple.comc5584f32010-08-27 20:49:02 +0000481#if ENABLE(FULLSCREEN_API)
jer.noble@apple.comc5584f32010-08-27 20:49:02 +0000482 , m_areKeysEnabledInFullScreen(0)
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +0000483 , m_fullScreenRenderer(0)
484 , m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired)
jer.noble@apple.comfed7d932011-05-23 22:22:27 +0000485 , m_isAnimatingFullScreen(false)
jer.noble@apple.comc5584f32010-08-27 20:49:02 +0000486#endif
eric.carlson@apple.com9c7fc722010-08-26 16:45:43 +0000487 , m_loadEventDelayCount(0)
jschuh@chromium.org47fb2f52010-10-04 22:25:43 +0000488 , m_loadEventDelayTimer(this, &Document::loadEventDelayTimerFired)
gavinp@chromium.org4b820562012-04-23 12:53:24 +0000489 , m_referrerPolicy(ReferrerPolicyDefault)
hyatt@apple.com3b5d20f02010-10-26 18:32:57 +0000490 , m_directionSetOnDocumentElement(false)
491 , m_writingModeSetOnDocumentElement(false)
commit-queue@webkit.orgb7b2b522011-02-02 00:22:52 +0000492 , m_writeRecursionIsTooDeep(false)
493 , m_writeRecursionDepth(0)
jonlee@apple.com8d909182011-05-16 17:25:02 +0000494 , m_wheelEventHandlerCount(0)
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +0000495#if ENABLE(TOUCH_EVENTS)
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +0000496 , m_touchEventHandlerCount(0)
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +0000497#endif
commit-queue@webkit.org5deb7492012-06-09 09:05:22 +0000498#if ENABLE(UNDO_MANAGER)
499 , m_undoManager(0)
500#endif
commit-queue@webkit.org160529f2011-12-07 23:41:21 +0000501 , m_pendingTasksTimer(this, &Document::pendingTasksTimerFired)
beidson@apple.comb1bc1b72012-04-20 21:29:00 +0000502 , m_scheduledTasksAreSuspended(false)
aestes@apple.com4544ec12012-04-24 07:43:40 +0000503 , m_visualUpdatesAllowed(true)
504 , m_visualUpdatesSuppressionTimer(this, &Document::visualUpdatesSuppressionTimerFired)
commit-queue@webkit.org7adcbd82012-05-02 13:00:47 +0000505#ifndef NDEBUG
506 , m_didDispatchViewportPropertiesChanged(false)
507#endif
ojan@chromium.org32aefb52011-11-11 19:14:25 +0000508{
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +0000509 m_document = this;
darinb9481ed2006-03-20 02:57:59 +0000510
511 m_printing = false;
hyatt@apple.com16a36002010-08-11 19:48:07 +0000512 m_paginatedForScreen = false;
513
adele@apple.comb68cb862008-06-17 18:45:06 +0000514 m_ignoreAutofocus = false;
darinb9481ed2006-03-20 02:57:59 +0000515
mjs22f8a1a2007-04-29 07:33:46 +0000516 m_frame = frame;
morrita@google.comac743042012-06-13 08:05:43 +0000517 if (m_frame)
518 provideContextFeaturesToDocumentFrom(this, m_frame->page());
darinb9481ed2006-03-20 02:57:59 +0000519
japhet@chromium.orgb254c9b2011-01-26 19:14:26 +0000520 // We depend on the url getting immediately set in subframes, but we
521 // also depend on the url NOT getting immediately set in opened windows.
522 // See fast/dom/early-frame-url.html
523 // and fast/dom/location-new-window-no-crash.html, respectively.
524 // FIXME: Can/should we unify this behavior?
525 if ((frame && frame->ownerElement()) || !url.isEmpty())
japhet@chromium.org6a088ce2010-06-25 17:17:45 +0000526 setURL(url);
527
darine775cf72006-07-09 22:48:56 +0000528 m_axObjectCache = 0;
dbates@webkit.org858331b2010-08-22 21:41:37 +0000529
levin@chromium.org5af8b192011-04-26 17:16:27 +0000530 m_markers = adoptPtr(new DocumentMarkerController);
dbates@webkit.org858331b2010-08-22 21:41:37 +0000531
levin@chromium.org5af8b192011-04-26 17:16:27 +0000532 m_cachedResourceLoader = adoptPtr(new CachedResourceLoader(this));
gavinp@chromium.orgaf445b92012-05-15 04:42:52 +0000533#if ENABLE(LINK_PRERENDER)
534 m_prerenderer = Prerenderer::create(this);
535#endif
commit-queue@webkit.org85cce8f2012-07-04 17:43:12 +0000536#if ENABLE(TEXT_AUTOSIZING)
537 m_textAutosizer = TextAutosizer::create(this);
538#endif
hyatt@apple.com0880de12010-01-28 17:47:30 +0000539 m_visuallyOrdered = false;
darinb9481ed2006-03-20 02:57:59 +0000540 m_bParsing = false;
ap2cb6b942006-11-20 19:56:38 +0000541 m_wellFormed = false;
darinb9481ed2006-03-20 02:57:59 +0000542
darinb9481ed2006-03-20 02:57:59 +0000543 m_textColor = Color::black;
darinb9481ed2006-03-20 02:57:59 +0000544 m_listenerTypes = 0;
darinb9481ed2006-03-20 02:57:59 +0000545 m_inStyleRecalc = false;
546 m_closeAfterStyleRecalc = false;
hyatt@apple.coma67f96a2009-07-15 17:02:30 +0000547
thatcher398012b2007-07-24 00:04:32 +0000548 m_gotoAnchorNeededAfterStylesheetsLoad = false;
abarth@webkit.org90a3ca62011-04-14 19:54:30 +0000549
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000550 m_didCalculateStyleResolver = false;
darinb9481ed2006-03-20 02:57:59 +0000551 m_ignorePendingStylesheets = false;
morrita@google.comcc735a72012-08-20 02:56:18 +0000552 m_needsNotifyRemoveAllPendingStylesheet = false;
anttifa58db352007-08-29 22:46:41 +0000553 m_hasNodesWithPlaceholderStyle = false;
hyatta9c6a342006-09-02 01:43:36 +0000554 m_pendingSheetLayout = NoLayoutWithPendingSheets;
darinb9481ed2006-03-20 02:57:59 +0000555
556 m_cssTarget = 0;
557
558 resetLinkColor();
559 resetVisitedLinkColor();
560 resetActiveLinkColor();
561
562 m_processingLoadEvent = false;
darinb9481ed2006-03-20 02:57:59 +0000563
abarth@webkit.org51aed8c2008-06-12 06:41:36 +0000564 initSecurityContext();
collinj@webkit.org9c672f62008-09-19 04:15:14 +0000565 initDNSPrefetch();
weinig343b6ff2007-08-07 03:08:53 +0000566
darinb9481ed2006-03-20 02:57:59 +0000567 static int docID = 0;
568 m_docID = docID++;
rniwa@webkit.orgfc3b7b72012-07-12 20:31:09 +0000569
570 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++)
571 m_nodeListCounts[i] = 0;
572
rniwa@webkit.org4823cc12012-07-09 17:40:09 +0000573 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_collections); i++)
574 m_collections[i] = 0;
575
yurys@chromium.org793b08e2012-02-17 08:33:30 +0000576 InspectorCounters::incrementCounter(InspectorCounters::DocumentCounter);
darinb9481ed2006-03-20 02:57:59 +0000577}
578
commit-queue@webkit.org2206b552011-11-15 01:23:35 +0000579static void histogramMutationEventUsage(const unsigned short& listenerTypes)
580{
commit-queue@webkit.orgbfdd4722011-12-17 00:58:33 +0000581 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMSubtreeModified", static_cast<bool>(listenerTypes & Document::DOMSUBTREEMODIFIED_LISTENER), 2);
582 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeInserted", static_cast<bool>(listenerTypes & Document::DOMNODEINSERTED_LISTENER), 2);
583 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeRemoved", static_cast<bool>(listenerTypes & Document::DOMNODEREMOVED_LISTENER), 2);
584 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeRemovedFromDocument", static_cast<bool>(listenerTypes & Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER), 2);
585 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMNodeInsertedIntoDocument", static_cast<bool>(listenerTypes & Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER), 2);
586 HistogramSupport::histogramEnumeration("DOMAPI.PerDocumentMutationEventUsage.DOMCharacterDataModified", static_cast<bool>(listenerTypes & Document::DOMCHARACTERDATAMODIFIED_LISTENER), 2);
commit-queue@webkit.org2206b552011-11-15 01:23:35 +0000587}
commit-queue@webkit.org2206b552011-11-15 01:23:35 +0000588
scheib@chromium.orge0e60032012-07-18 20:06:12 +0000589#if ENABLE(FULLSCREEN_API)
590static bool isAttributeOnAllOwners(const WebCore::QualifiedName& attribute, const HTMLFrameOwnerElement* owner)
591{
592 if (!owner)
593 return true;
594 do {
595 if (!owner->hasAttribute(attribute))
596 return false;
597 } while ((owner = owner->document()->ownerElement()));
598 return true;
599}
600#endif
601
darinb9481ed2006-03-20 02:57:59 +0000602Document::~Document()
603{
beidsonddbaead2006-12-13 23:34:09 +0000604 ASSERT(!renderer());
605 ASSERT(!m_inPageCache);
606 ASSERT(!m_savedRenderer);
darin@apple.comf28fa1b2008-03-15 17:26:28 +0000607 ASSERT(m_ranges.isEmpty());
hyatt@apple.comdcf36332009-04-10 03:15:05 +0000608 ASSERT(!m_styleRecalcTimer.isActive());
rolandsteiner@chromium.org05d94232011-04-08 22:37:39 +0000609 ASSERT(!m_parentTreeScope);
rolandsteiner@chromium.orgd9055462011-04-20 17:25:33 +0000610 ASSERT(!m_guardRefCount);
beidsonddbaead2006-12-13 23:34:09 +0000611
abarth@webkit.org7d4cb042012-08-17 00:29:35 +0000612 // FIXME: Should we reset m_domWindow when we detach from the Frame?
abarth@webkit.org23ea90a2012-08-14 19:47:59 +0000613 if (m_domWindow)
abarth@webkit.org7d4cb042012-08-17 00:29:35 +0000614 m_domWindow->resetUnlessSuspendedForPageCache();
abarth@webkit.org23ea90a2012-08-14 19:47:59 +0000615
simonjam@chromium.org5871a052011-03-16 00:00:09 +0000616 m_scriptRunner.clear();
mitz@apple.com73169a12009-04-20 04:20:08 +0000617
commit-queue@webkit.org2206b552011-11-15 01:23:35 +0000618 histogramMutationEventUsage(m_listenerTypes);
commit-queue@webkit.org2206b552011-11-15 01:23:35 +0000619
beidsonddbaead2006-12-13 23:34:09 +0000620 removeAllEventListeners();
darinb9481ed2006-03-20 02:57:59 +0000621
eric@webkit.org0cea84c2010-08-19 19:32:02 +0000622 // Currently we believe that Document can never outlive the parser.
623 // Although the Document may be replaced synchronously, DocumentParsers
624 // generally keep at least one reference to an Element which would in turn
625 // has a reference to the Document. If you hit this ASSERT, then that
626 // assumption is wrong. DocumentParser::detach() should ensure that even
627 // if the DocumentParser outlives the Document it won't cause badness.
628 ASSERT(!m_parser || m_parser->refCount() == 1);
629 detachParser();
abarth@webkit.orge5cb28e2009-12-04 05:28:33 +0000630
abarth@webkit.org3e035352009-12-04 05:54:58 +0000631 m_renderArena.clear();
darinb9481ed2006-03-20 02:57:59 +0000632
harrison@apple.com7954df22008-03-12 16:16:40 +0000633 clearAXObjectCache();
634
darinb9481ed2006-03-20 02:57:59 +0000635 m_decoder = 0;
paroga@webkit.orga91ac212010-11-23 00:55:59 +0000636
antti@apple.com8a2e6f02012-09-25 04:25:35 +0000637 if (m_styleSheetList)
638 m_styleSheetList->detachFromDocument();
639
antti@apple.come5a88a72012-09-24 22:14:47 +0000640 m_styleSheetCollection.clear();
dimich@chromium.org948b9a32010-01-15 21:47:15 +0000641
commit-queue@webkit.org5323f762012-07-13 10:01:38 +0000642 if (m_namedFlows)
643 m_namedFlows->documentDestroyed();
644
ap@apple.com1fe90892010-11-10 21:12:39 +0000645 if (m_elemSheet)
646 m_elemSheet->clearOwnerNode();
ap@apple.com1fe90892010-11-10 21:12:39 +0000647
commit-queue@webkit.orgdef1a492012-09-07 22:58:56 +0000648 deleteCustomFonts();
649
dimich@chromium.org948b9a32010-01-15 21:47:15 +0000650 m_weakReference->clear();
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +0000651
652 if (m_mediaQueryMatcher)
653 m_mediaQueryMatcher->documentDestroyed();
hayato@chromium.org81596e42012-02-02 04:21:29 +0000654
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000655 clearStyleResolver(); // We need to destory CSSFontSelector before destroying m_cachedResourceLoader.
rniwa@webkit.org1c7df642012-02-10 03:34:21 +0000656 m_cachedResourceLoader.clear();
657
hayato@chromium.org81596e42012-02-02 04:21:29 +0000658 // We must call clearRareData() here since a Document class inherits TreeScope
659 // as well as Node. See a comment on TreeScope.h for the reason.
660 if (hasRareData())
661 clearRareData();
yurys@chromium.org793b08e2012-02-17 08:33:30 +0000662
rniwa@webkit.orgfc3b7b72012-07-12 20:31:09 +0000663 ASSERT(!m_listsInvalidatedAtDocument.size());
664
665 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_nodeListCounts); i++)
666 ASSERT(!m_nodeListCounts[i]);
667
668 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_collections); i++)
669 ASSERT(!m_collections[i]);
670
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +0000671 m_document = 0;
haraken@chromium.orgabf5d022012-06-28 06:29:27 +0000672
yurys@chromium.org793b08e2012-02-17 08:33:30 +0000673 InspectorCounters::decrementCounter(InspectorCounters::DocumentCounter);
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +0000674}
675
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000676void Document::removedLastRef()
677{
haraken@chromium.org971871a2012-06-08 09:19:39 +0000678 ASSERT(!m_deletionHasBegun);
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000679 if (m_guardRefCount) {
680 // If removing a child removes the last self-only ref, we don't
681 // want the scope to be destructed until after
682 // removeAllChildren returns, so we guard ourselves with an
683 // extra self-only ref.
684 guardRef();
685
686 // We must make sure not to be retaining any of our children through
687 // these extra pointers or we will create a reference cycle.
688 m_docType = 0;
689 m_focusedNode = 0;
690 m_hoverNode = 0;
691 m_activeNode = 0;
692 m_titleElement = 0;
693 m_documentElement = 0;
morrita@google.comac743042012-06-13 08:05:43 +0000694 m_contextFeatures = ContextFeatures::defaultSwitch();
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000695#if ENABLE(FULLSCREEN_API)
696 m_fullScreenElement = 0;
jer.noble@apple.com26cf8702012-03-16 18:12:14 +0000697 m_fullScreenElementStack.clear();
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000698#endif
699
jpfau@apple.comb601f182012-06-04 23:38:33 +0000700 detachParser();
701
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000702 // removeAllChildren() doesn't always unregister IDs,
703 // so tear down scope information upfront to avoid having stale references in the map.
704 destroyTreeScopeData();
705 removeAllChildren();
706
707 m_markers->detach();
708
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000709 m_cssCanvasElements.clear();
710
711#if ENABLE(REQUEST_ANIMATION_FRAME)
712 // FIXME: consider using ActiveDOMObject.
jamesr@google.coma5d3c9e2011-12-09 01:33:41 +0000713 if (m_scriptedAnimationController)
714 m_scriptedAnimationController->clearDocumentPointer();
715 m_scriptedAnimationController.clear();
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000716#endif
717
718#ifndef NDEBUG
719 m_inRemovedLastRefFunction = false;
720#endif
721
722 guardDeref();
723 } else {
haraken@chromium.org971871a2012-06-08 09:19:39 +0000724#ifndef NDEBUG
725 m_deletionHasBegun = true;
726#endif
rolandsteiner@chromium.orgdafa6102011-04-06 23:52:52 +0000727 delete this;
728 }
729}
730
rolandsteiner@chromium.orga3cbe772011-04-04 22:25:18 +0000731Element* Document::getElementById(const AtomicString& id) const
732{
733 return TreeScope::getElementById(id);
734}
735
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000736Element* Document::getElementByAccessKey(const String& key)
737{
738 if (key.isEmpty())
739 return 0;
740 if (!m_accessKeyMapValid) {
741 buildAccessKeyMap(this);
742 m_accessKeyMapValid = true;
743 }
744 return m_elementsByAccessKey.get(key.impl());
745}
746
hayato@chromium.org81596e42012-02-02 04:21:29 +0000747void Document::buildAccessKeyMap(TreeScope* scope)
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000748{
hayato@chromium.org81596e42012-02-02 04:21:29 +0000749 ASSERT(scope);
750 Node* rootNode = scope->rootNode();
751 for (Node* node = rootNode; node; node = node->traverseNextNode(rootNode)) {
752 if (!node->isElementNode())
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000753 continue;
hayato@chromium.org81596e42012-02-02 04:21:29 +0000754 Element* element = static_cast<Element*>(node);
commit-queue@webkit.org03477c82011-09-02 17:07:51 +0000755 const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000756 if (!accessKey.isEmpty())
757 m_elementsByAccessKey.set(accessKey.impl(), element);
commit-queue@webkit.org36762182012-02-14 12:48:24 +0000758
morrita@google.come2004212012-05-21 16:59:02 +0000759 for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot())
760 buildAccessKeyMap(root);
rolandsteiner@chromium.orga8fbd632011-05-03 23:08:21 +0000761 }
762}
763
764void Document::invalidateAccessKeyMap()
765{
766 m_accessKeyMapValid = false;
767 m_elementsByAccessKey.clear();
768}
769
haraken@chromium.org3981f522012-06-02 19:23:25 +0000770SelectorQueryCache* Document::selectorQueryCache()
771{
772 if (!m_selectorQueryCache)
773 m_selectorQueryCache = adoptPtr(new SelectorQueryCache());
774 return m_selectorQueryCache.get();
775}
776
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +0000777MediaQueryMatcher* Document::mediaQueryMatcher()
778{
779 if (!m_mediaQueryMatcher)
780 m_mediaQueryMatcher = MediaQueryMatcher::create(this);
781 return m_mediaQueryMatcher.get();
darinb9481ed2006-03-20 02:57:59 +0000782}
783
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000784void Document::setCompatibilityMode(CompatibilityMode mode)
785{
786 if (m_compatibilityModeLocked || mode == m_compatibilityMode)
787 return;
antti@apple.com8a2e6f02012-09-25 04:25:35 +0000788 ASSERT(m_styleSheetCollection->authorStyleSheets().isEmpty());
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000789 bool wasInQuirksMode = inQuirksMode();
790 m_compatibilityMode = mode;
haraken@chromium.org3981f522012-06-02 19:23:25 +0000791 selectorQueryCache()->invalidate();
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000792 if (inQuirksMode() != wasInQuirksMode) {
793 // All user stylesheets have to reparse using the different mode.
antti@apple.come5a88a72012-09-24 22:14:47 +0000794 m_styleSheetCollection->clearPageUserSheet();
795 m_styleSheetCollection->clearPageGroupUserSheets();
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +0000796 }
797}
798
abarth@webkit.orgd33c9372010-09-14 23:27:19 +0000799String Document::compatMode() const
800{
801 return inQuirksMode() ? "BackCompat" : "CSS1Compat";
802}
803
darinb9481ed2006-03-20 02:57:59 +0000804void Document::resetLinkColor()
805{
806 m_linkColor = Color(0, 0, 238);
807}
808
809void Document::resetVisitedLinkColor()
810{
811 m_visitedLinkColor = Color(85, 26, 139);
812}
813
814void Document::resetActiveLinkColor()
815{
eseidelcff0a722006-03-22 22:27:45 +0000816 m_activeLinkColor.setNamedColor("red");
darinb9481ed2006-03-20 02:57:59 +0000817}
818
819void Document::setDocType(PassRefPtr<DocumentType> docType)
820{
hyatt@apple.com42583072008-02-20 22:47:57 +0000821 // This should never be called more than once.
hyatt@apple.com42583072008-02-20 22:47:57 +0000822 ASSERT(!m_docType || !docType);
darinb9481ed2006-03-20 02:57:59 +0000823 m_docType = docType;
commit-queue@webkit.org7736e172012-05-09 23:10:21 +0000824 if (m_docType) {
morrita@google.come08d15a2012-01-10 02:11:30 +0000825 this->adoptIfNeeded(m_docType.get());
commit-queue@webkit.org38d67852012-06-05 03:01:18 +0000826#if ENABLE(LEGACY_VIEWPORT_ADAPTION)
commit-queue@webkit.org7736e172012-05-09 23:10:21 +0000827 if (m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", /* caseSensitive */ false))
commit-queue@webkit.org36e5ae12012-06-01 18:24:02 +0000828 processViewport("width=device-width, height=device-height", ViewportArguments::XHTMLMobileProfile);
commit-queue@webkit.org7736e172012-05-09 23:10:21 +0000829#endif
830 }
antti@apple.com0a03deb2012-01-06 14:48:23 +0000831 // Doctype affects the interpretation of the stylesheets.
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000832 clearStyleResolver();
darinb9481ed2006-03-20 02:57:59 +0000833}
834
antonm@chromium.org305e54d2011-02-21 16:01:41 +0000835DOMImplementation* Document::implementation()
darinb9481ed2006-03-20 02:57:59 +0000836{
weinig@apple.com3feb4c32008-06-15 21:53:29 +0000837 if (!m_implementation)
antonm@chromium.org305e54d2011-02-21 16:01:41 +0000838 m_implementation = DOMImplementation::create(this);
darinb9481ed2006-03-20 02:57:59 +0000839 return m_implementation.get();
840}
841
hyatt@apple.com86b942b2008-02-27 23:13:51 +0000842void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
thatchere6e3e562006-07-09 07:56:54 +0000843{
hayato@chromium.org81596e42012-02-02 04:21:29 +0000844 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
hyatt@apple.com86b942b2008-02-27 23:13:51 +0000845
antti@apple.com70726ab2012-01-08 11:45:58 +0000846 Element* newDocumentElement = firstElementChild(this);
847 if (newDocumentElement == m_documentElement)
848 return;
849 m_documentElement = newDocumentElement;
850 // The root style used for media query matching depends on the document element.
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000851 clearStyleResolver();
darinb9481ed2006-03-20 02:57:59 +0000852}
853
mjs@apple.com773874c2008-03-30 04:58:08 +0000854PassRefPtr<Element> Document::createElement(const AtomicString& name, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +0000855{
eric@webkit.org4e5ae832008-03-22 09:49:58 +0000856 if (!isValidName(name)) {
857 ec = INVALID_CHARACTER_ERR;
858 return 0;
859 }
kmcculloc19b2792007-08-08 17:14:42 +0000860
eric@webkit.org4e5ae832008-03-22 09:49:58 +0000861 if (m_isXHTML)
jchaffraix@webkit.org6d046192008-11-24 19:29:39 +0000862 return HTMLElementFactory::createHTMLElement(QualifiedName(nullAtom, name, xhtmlNamespaceURI), this, 0, false);
eric@webkit.org4e5ae832008-03-22 09:49:58 +0000863
jchaffraix@webkit.org0ad36c32009-02-12 20:52:02 +0000864 return createElement(QualifiedName(nullAtom, name, nullAtom), false);
darinb9481ed2006-03-20 02:57:59 +0000865}
866
867PassRefPtr<DocumentFragment> Document::createDocumentFragment()
868{
darin@apple.com7e131b62009-08-15 06:25:49 +0000869 return DocumentFragment::create(document());
darinb9481ed2006-03-20 02:57:59 +0000870}
871
darin@apple.com48ac3c42008-06-14 08:46:51 +0000872PassRefPtr<Text> Document::createTextNode(const String& data)
darinb9481ed2006-03-20 02:57:59 +0000873{
darin@apple.com7e131b62009-08-15 06:25:49 +0000874 return Text::create(this, data);
darinb9481ed2006-03-20 02:57:59 +0000875}
876
darin@apple.com48ac3c42008-06-14 08:46:51 +0000877PassRefPtr<Comment> Document::createComment(const String& data)
darinb9481ed2006-03-20 02:57:59 +0000878{
darin@apple.com7e131b62009-08-15 06:25:49 +0000879 return Comment::create(this, data);
darinb9481ed2006-03-20 02:57:59 +0000880}
881
darin@apple.com48ac3c42008-06-14 08:46:51 +0000882PassRefPtr<CDATASection> Document::createCDATASection(const String& data, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +0000883{
884 if (isHTMLDocument()) {
885 ec = NOT_SUPPORTED_ERR;
886 return 0;
887 }
darin@apple.com7e131b62009-08-15 06:25:49 +0000888 return CDATASection::create(this, data);
darinb9481ed2006-03-20 02:57:59 +0000889}
890
darin@apple.com48ac3c42008-06-14 08:46:51 +0000891PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String& target, const String& data, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +0000892{
893 if (!isValidName(target)) {
894 ec = INVALID_CHARACTER_ERR;
895 return 0;
896 }
897 if (isHTMLDocument()) {
898 ec = NOT_SUPPORTED_ERR;
899 return 0;
900 }
darin@apple.com7e131b62009-08-15 06:25:49 +0000901 return ProcessingInstruction::create(this, target, data);
darinb9481ed2006-03-20 02:57:59 +0000902}
903
darin@apple.com48ac3c42008-06-14 08:46:51 +0000904PassRefPtr<EntityReference> Document::createEntityReference(const String& name, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +0000905{
906 if (!isValidName(name)) {
907 ec = INVALID_CHARACTER_ERR;
908 return 0;
909 }
910 if (isHTMLDocument()) {
911 ec = NOT_SUPPORTED_ERR;
912 return 0;
913 }
darin@apple.com7e131b62009-08-15 06:25:49 +0000914 return EntityReference::create(this, name);
darinb9481ed2006-03-20 02:57:59 +0000915}
916
darin@apple.com48ac3c42008-06-14 08:46:51 +0000917PassRefPtr<EditingText> Document::createEditingTextNode(const String& text)
darinb9481ed2006-03-20 02:57:59 +0000918{
darin@apple.com7e131b62009-08-15 06:25:49 +0000919 return EditingText::create(this, text);
darinb9481ed2006-03-20 02:57:59 +0000920}
921
922PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
923{
antti@apple.come89e04d2012-02-03 19:46:48 +0000924 return StylePropertySet::create()->ensureCSSStyleDeclaration();
darinb9481ed2006-03-20 02:57:59 +0000925}
926
927PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
928{
929 ec = 0;
ggaren59d1d762006-04-22 07:33:04 +0000930
timothy_horton@apple.com69736612012-02-24 19:39:01 +0000931 if (!importedNode) {
ggaren59d1d762006-04-22 07:33:04 +0000932 ec = NOT_SUPPORTED_ERR;
933 return 0;
934 }
darinb9481ed2006-03-20 02:57:59 +0000935
936 switch (importedNode->nodeType()) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000937 case TEXT_NODE:
938 return createTextNode(importedNode->nodeValue());
939 case CDATA_SECTION_NODE:
940 return createCDATASection(importedNode->nodeValue(), ec);
941 case ENTITY_REFERENCE_NODE:
942 return createEntityReference(importedNode->nodeName(), ec);
943 case PROCESSING_INSTRUCTION_NODE:
944 return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec);
945 case COMMENT_NODE:
946 return createComment(importedNode->nodeValue());
947 case ELEMENT_NODE: {
948 Element* oldElement = static_cast<Element*>(importedNode);
tkent@chromium.org02045fa2012-01-06 08:47:18 +0000949 // FIXME: The following check might be unnecessary. Is it possible that
950 // oldElement has mismatched prefix/namespace?
abarth@webkit.org427e9f12012-01-19 08:31:13 +0000951 if (!hasValidNamespaceForElements(oldElement->tagQName())) {
tkent@chromium.org02045fa2012-01-06 08:47:18 +0000952 ec = NAMESPACE_ERR;
953 return 0;
954 }
955 RefPtr<Element> newElement = createElement(oldElement->tagQName(), ec);
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000956 if (ec)
957 return 0;
darinb9481ed2006-03-20 02:57:59 +0000958
kling@webkit.orgc4ff9762012-05-16 19:31:40 +0000959 newElement->cloneDataFromElement(*oldElement);
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000960
961 if (deep) {
962 for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
963 RefPtr<Node> newChild = importNode(oldChild, true, ec);
964 if (ec)
965 return 0;
966 newElement->appendChild(newChild.release(), ec);
967 if (ec)
968 return 0;
ap4af4d7f2007-10-25 18:31:32 +0000969 }
ap4af4d7f2007-10-25 18:31:32 +0000970 }
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000971
972 return newElement.release();
973 }
974 case ATTRIBUTE_NODE:
kling@webkit.orge3f8e9d2012-04-23 05:40:02 +0000975 return Attr::create(this, QualifiedName(nullAtom, static_cast<Attr*>(importedNode)->name(), nullAtom), static_cast<Attr*>(importedNode)->value());
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000976 case DOCUMENT_FRAGMENT_NODE: {
hayato@chromium.org14993e02012-02-14 11:32:12 +0000977 if (importedNode->isShadowRoot()) {
978 // ShadowRoot nodes should not be explicitly importable.
979 // Either they are imported along with their host node, or created implicitly.
980 break;
981 }
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +0000982 DocumentFragment* oldFragment = static_cast<DocumentFragment*>(importedNode);
983 RefPtr<DocumentFragment> newFragment = createDocumentFragment();
984 if (deep) {
985 for (Node* oldChild = oldFragment->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
986 RefPtr<Node> newChild = importNode(oldChild, true, ec);
987 if (ec)
988 return 0;
989 newFragment->appendChild(newChild.release(), ec);
990 if (ec)
991 return 0;
992 }
993 }
994
995 return newFragment.release();
996 }
997 case ENTITY_NODE:
998 case NOTATION_NODE:
999 // FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that.
1000 // Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM.
1001 case DOCUMENT_NODE:
1002 case DOCUMENT_TYPE_NODE:
1003 case XPATH_NAMESPACE_NODE:
1004 break;
darinb9481ed2006-03-20 02:57:59 +00001005 }
darinb9481ed2006-03-20 02:57:59 +00001006 ec = NOT_SUPPORTED_ERR;
1007 return 0;
1008}
1009
1010
1011PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
1012{
ggaren59d1d762006-04-22 07:33:04 +00001013 if (!source) {
1014 ec = NOT_SUPPORTED_ERR;
darinb9481ed2006-03-20 02:57:59 +00001015 return 0;
ggaren59d1d762006-04-22 07:33:04 +00001016 }
eric@webkit.org62f0c4a2008-02-08 09:04:22 +00001017
1018 if (source->isReadOnlyNode()) {
1019 ec = NO_MODIFICATION_ALLOWED_ERR;
1020 return 0;
1021 }
1022
ojan@chromium.org5570e702011-03-04 06:20:57 +00001023 EventQueueScope scope;
1024
darinb9481ed2006-03-20 02:57:59 +00001025 switch (source->nodeType()) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00001026 case ENTITY_NODE:
1027 case NOTATION_NODE:
1028 case DOCUMENT_NODE:
1029 case DOCUMENT_TYPE_NODE:
1030 case XPATH_NAMESPACE_NODE:
1031 ec = NOT_SUPPORTED_ERR;
1032 return 0;
1033 case ATTRIBUTE_NODE: {
1034 Attr* attr = static_cast<Attr*>(source.get());
1035 if (attr->ownerElement())
1036 attr->ownerElement()->removeAttributeNode(attr, ec);
1037 attr->setSpecified(true);
1038 break;
1039 }
1040 default:
morrita@google.com73798562012-04-18 04:52:47 +00001041 if (source->isShadowRoot()) {
1042 // ShadowRoot cannot disconnect itself from the host node.
1043 ec = HIERARCHY_REQUEST_ERR;
1044 return 0;
1045 }
1046
abarth@webkit.org8c9fac62012-03-20 05:58:36 +00001047 // FIXME: What about <frame> and <object>?
rniwa@webkit.orga89a67a2011-01-08 00:49:52 +00001048 if (source->hasTagName(iframeTag)) {
1049 HTMLIFrameElement* iframe = static_cast<HTMLIFrameElement*>(source.get());
rniwa@webkit.orga80cad02011-01-08 02:42:44 +00001050 if (frame() && frame()->tree()->isDescendantOf(iframe->contentFrame())) {
rniwa@webkit.orga89a67a2011-01-08 00:49:52 +00001051 ec = HIERARCHY_REQUEST_ERR;
1052 return 0;
1053 }
rniwa@webkit.orga89a67a2011-01-08 00:49:52 +00001054 }
morrita@google.com790f7e62012-09-25 08:01:17 +00001055 if (source->parentNode()) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00001056 source->parentNode()->removeChild(source.get(), ec);
morrita@google.com790f7e62012-09-25 08:01:17 +00001057 if (ec)
1058 return 0;
1059 }
darinb9481ed2006-03-20 02:57:59 +00001060 }
dglazkov@chromium.orgdbe91102011-01-13 23:38:32 +00001061
morrita@google.come08d15a2012-01-10 02:11:30 +00001062 this->adoptIfNeeded(source.get());
darinb9481ed2006-03-20 02:57:59 +00001063
1064 return source;
1065}
1066
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001067bool Document::hasValidNamespaceForElements(const QualifiedName& qName)
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001068{
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001069 // These checks are from DOM Core Level 2, createElementNS
1070 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001071 if (!qName.prefix().isEmpty() && qName.namespaceURI().isNull()) // createElementNS(null, "html:div")
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001072 return false;
ap@apple.com38221c62010-01-18 22:05:55 +00001073 if (qName.prefix() == xmlAtom && qName.namespaceURI() != XMLNames::xmlNamespaceURI) // createElementNS("http://www.example.com", "xml:lang")
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001074 return false;
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001075
1076 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
1077 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1078 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"), createElementNS(null, "xmlns:bar")
ap@apple.com38221c62010-01-18 22:05:55 +00001079 if ((qName.prefix() == xmlnsAtom && qName.namespaceURI() != XMLNSNames::xmlnsNamespaceURI) || (qName.prefix() != xmlnsAtom && qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI))
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001080 return false;
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001081
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001082 return true;
1083}
1084
1085bool Document::hasValidNamespaceForAttributes(const QualifiedName& qName)
1086{
1087 // Spec: DOM Level 2 Core: http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-ElSetAttrNS
1088 if (qName.prefix().isEmpty() && qName.localName() == xmlnsAtom) {
1089 // Note: The case of an "xmlns" qualified name with a namespace of
1090 // xmlnsNamespaceURI is specifically allowed (See <http://www.w3.org/2000/xmlns/>).
1091 return qName.namespaceURI() == XMLNSNames::xmlnsNamespaceURI;
1092 }
1093 return hasValidNamespaceForElements(qName);
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001094}
1095
anderscaddd35422007-01-29 22:42:59 +00001096// FIXME: This should really be in a possible ElementFactory class
jchaffraix@webkit.org0ad36c32009-02-12 20:52:02 +00001097PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser)
anderscaddd35422007-01-29 22:42:59 +00001098{
1099 RefPtr<Element> e;
1100
1101 // FIXME: Use registered namespaces and look up in a hash to find the right factory.
1102 if (qName.namespaceURI() == xhtmlNamespaceURI)
jchaffraix@webkit.org6d046192008-11-24 19:29:39 +00001103 e = HTMLElementFactory::createHTMLElement(qName, this, 0, createdByParser);
mjsd2948ef2007-02-26 19:29:04 +00001104#if ENABLE(SVG)
anderscaddd35422007-01-29 22:42:59 +00001105 else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
1106 e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
1107#endif
eric@webkit.org8af95f32009-09-19 18:02:33 +00001108#if ENABLE(MATHML)
1109 else if (qName.namespaceURI() == MathMLNames::mathmlNamespaceURI)
1110 e = MathMLElementFactory::createMathMLElement(qName, this, createdByParser);
1111#endif
darin@apple.comf5247d12010-06-13 17:29:10 +00001112
pfeldman@chromium.org81b45e52011-02-28 15:26:44 +00001113 if (e)
1114 m_sawElementsInKnownNamespaces = true;
1115 else
darin@apple.comcf9dd0f2009-08-23 06:55:57 +00001116 e = Element::create(qName, document());
jchaffraix@webkit.org0ad36c32009-02-12 20:52:02 +00001117
1118 // <image> uses imgTag so we need a special rule.
1119 ASSERT((qName.matches(imageTag) && e->tagQName().matches(imgTag) && e->tagQName().prefix() == qName.prefix()) || qName == e->tagQName());
1120
anderscaddd35422007-01-29 22:42:59 +00001121 return e.release();
1122}
1123
hyatt@apple.com6c8a73ab2012-03-16 19:55:25 +00001124bool Document::regionBasedColumnsEnabled() const
1125{
1126 return settings() && settings()->regionBasedColumnsEnabled();
1127}
1128
ojan@chromium.org52498d72012-09-14 22:49:38 +00001129bool Document::cssStickyPositionEnabled() const
1130{
1131 return settings() && settings()->cssStickyPositionEnabled();
1132}
1133
mihnea@adobe.com83fafcd2012-02-17 20:44:00 +00001134bool Document::cssRegionsEnabled() const
1135{
1136 return settings() && settings()->cssRegionsEnabled();
1137}
1138
tony@chromium.org6a48fa02012-05-18 19:23:14 +00001139bool Document::cssGridLayoutEnabled() const
1140{
1141 return settings() && settings()->cssGridLayoutEnabled();
1142}
1143
timothy_horton@apple.com3f03ac12012-05-25 06:53:27 +00001144#if ENABLE(CSS_REGIONS)
1145
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +00001146PassRefPtr<DOMNamedFlowCollection> Document::webkitGetNamedFlows()
1147{
1148 if (!cssRegionsEnabled() || !renderer())
1149 return 0;
1150
1151 updateStyleIfNeeded();
1152
1153 return namedFlows()->createCSSOMSnapshot();
1154}
1155
timothy_horton@apple.com3f03ac12012-05-25 06:53:27 +00001156#endif
1157
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +00001158NamedFlowCollection* Document::namedFlows()
commit-queue@webkit.org5323f762012-07-13 10:01:38 +00001159{
1160 if (!m_namedFlows)
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +00001161 m_namedFlows = NamedFlowCollection::create(this);
commit-queue@webkit.org5323f762012-07-13 10:01:38 +00001162
1163 return m_namedFlows.get();
1164}
1165
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001166PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00001167{
darinb9481ed2006-03-20 02:57:59 +00001168 String prefix, localName;
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00001169 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
darinb9481ed2006-03-20 02:57:59 +00001170 return 0;
darinb9481ed2006-03-20 02:57:59 +00001171
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001172 QualifiedName qName(prefix, localName, namespaceURI);
abarth@webkit.org427e9f12012-01-19 08:31:13 +00001173 if (!hasValidNamespaceForElements(qName)) {
eric@webkit.org4e5ae832008-03-22 09:49:58 +00001174 ec = NAMESPACE_ERR;
1175 return 0;
1176 }
1177
jchaffraix@webkit.org0ad36c32009-02-12 20:52:02 +00001178 return createElement(qName, false);
darinb9481ed2006-03-20 02:57:59 +00001179}
1180
darin4a244792006-05-05 15:22:33 +00001181String Document::readyState() const
mjs9d8e6952006-04-05 22:26:43 +00001182{
abarth@webkit.orgb1e7d632012-08-29 23:04:26 +00001183 DEFINE_STATIC_LOCAL(const String, loading, (ASCIILiteral("loading")));
1184 DEFINE_STATIC_LOCAL(const String, interactive, (ASCIILiteral("interactive")));
1185 DEFINE_STATIC_LOCAL(const String, complete, (ASCIILiteral("complete")));
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00001186
1187 switch (m_readyState) {
1188 case Loading:
1189 return loading;
1190 case Interactive:
1191 return interactive;
1192 case Complete:
1193 return complete;
mjs9d8e6952006-04-05 22:26:43 +00001194 }
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00001195
1196 ASSERT_NOT_REACHED();
mjs9d8e6952006-04-05 22:26:43 +00001197 return String();
1198}
1199
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00001200void Document::setReadyState(ReadyState readyState)
1201{
commit-queue@webkit.org53b27b52010-10-13 23:10:56 +00001202 if (readyState == m_readyState)
1203 return;
commit-queue@webkit.orgd63bb0a2010-11-04 08:36:17 +00001204
1205 switch (readyState) {
1206 case Loading:
1207 if (!m_documentTiming.domLoading)
simonjam@chromium.orgdfab5cf2011-12-15 18:45:29 +00001208 m_documentTiming.domLoading = monotonicallyIncreasingTime();
commit-queue@webkit.orgd63bb0a2010-11-04 08:36:17 +00001209 break;
1210 case Interactive:
1211 if (!m_documentTiming.domInteractive)
simonjam@chromium.orgdfab5cf2011-12-15 18:45:29 +00001212 m_documentTiming.domInteractive = monotonicallyIncreasingTime();
commit-queue@webkit.orgd63bb0a2010-11-04 08:36:17 +00001213 break;
1214 case Complete:
1215 if (!m_documentTiming.domComplete)
simonjam@chromium.orgdfab5cf2011-12-15 18:45:29 +00001216 m_documentTiming.domComplete = monotonicallyIncreasingTime();
commit-queue@webkit.orgd63bb0a2010-11-04 08:36:17 +00001217 break;
1218 }
1219
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00001220 m_readyState = readyState;
commit-queue@webkit.org53b27b52010-10-13 23:10:56 +00001221 dispatchEvent(Event::create(eventNames().readystatechangeEvent, false, false));
aestes@apple.com4544ec12012-04-24 07:43:40 +00001222
1223 if (settings() && settings()->suppressesIncrementalRendering())
1224 setVisualUpdatesAllowed(readyState);
1225}
1226
1227void Document::setVisualUpdatesAllowed(ReadyState readyState)
1228{
1229 ASSERT(settings() && settings()->suppressesIncrementalRendering());
1230 switch (readyState) {
1231 case Loading:
1232 ASSERT(!m_visualUpdatesSuppressionTimer.isActive());
1233 ASSERT(m_visualUpdatesAllowed);
1234 m_visualUpdatesSuppressionTimer.startOneShot(settings()->incrementalRenderingSuppressionTimeoutInSeconds());
1235 setVisualUpdatesAllowed(false);
1236 break;
1237 case Interactive:
1238 ASSERT(m_visualUpdatesSuppressionTimer.isActive() || m_visualUpdatesAllowed);
1239 break;
1240 case Complete:
1241 if (m_visualUpdatesSuppressionTimer.isActive()) {
1242 ASSERT(!m_visualUpdatesAllowed);
1243 m_visualUpdatesSuppressionTimer.stop();
1244 setVisualUpdatesAllowed(true);
1245 } else
1246 ASSERT(m_visualUpdatesAllowed);
1247 break;
1248 }
1249}
1250
1251void Document::setVisualUpdatesAllowed(bool visualUpdatesAllowed)
1252{
1253 if (m_visualUpdatesAllowed == visualUpdatesAllowed)
1254 return;
1255
1256 m_visualUpdatesAllowed = visualUpdatesAllowed;
1257
1258 if (!visualUpdatesAllowed)
1259 return;
1260
1261#if USE(ACCELERATED_COMPOSITING)
1262 if (view())
1263 view()->updateCompositingLayersAfterLayout();
1264#endif
1265
1266 if (renderer())
1267 renderer()->repaint();
1268}
1269
1270void Document::visualUpdatesSuppressionTimerFired(Timer<Document>*)
1271{
1272 ASSERT(!m_visualUpdatesAllowed);
1273 setVisualUpdatesAllowed(true);
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00001274}
1275
dimich@chromium.orge1c03922009-03-06 21:21:06 +00001276String Document::encoding() const
mjs9d8e6952006-04-05 22:26:43 +00001277{
darin5b2cbe12006-10-30 00:57:20 +00001278 if (TextResourceDecoder* d = decoder())
eric@webkit.org19fc1982009-05-06 05:37:54 +00001279 return d->encoding().domName();
mjs9d8e6952006-04-05 22:26:43 +00001280 return String();
1281}
1282
darin4a244792006-05-05 15:22:33 +00001283String Document::defaultCharset() const
mjs9d8e6952006-04-05 22:26:43 +00001284{
ggaren6ad6e762007-05-25 09:13:32 +00001285 if (Settings* settings = this->settings())
1286 return settings->defaultTextEncodingName();
mjs9d8e6952006-04-05 22:26:43 +00001287 return String();
1288}
1289
1290void Document::setCharset(const String& charset)
1291{
1292 if (!decoder())
1293 return;
darin5b2cbe12006-10-30 00:57:20 +00001294 decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
mjs9d8e6952006-04-05 22:26:43 +00001295}
1296
commit-queue@webkit.org335d75e2012-02-03 07:30:20 +00001297void Document::setContentLanguage(const String& language)
1298{
1299 if (m_contentLanguage == language)
1300 return;
1301 m_contentLanguage = language;
1302
1303 // Recalculate style so language is used when selecting the initial font.
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00001304 styleResolverChanged(DeferRecalcStyle);
commit-queue@webkit.org335d75e2012-02-03 07:30:20 +00001305}
1306
ap0289d282006-11-20 18:59:12 +00001307void Document::setXMLVersion(const String& version, ExceptionCode& ec)
1308{
ap0289d282006-11-20 18:59:12 +00001309 if (!implementation()->hasFeature("XML", String())) {
1310 ec = NOT_SUPPORTED_ERR;
1311 return;
1312 }
andreas.kling@nokia.com38277de2010-08-24 08:55:29 +00001313
1314 if (!XMLDocumentParser::supportsXMLVersion(version)) {
1315 ec = NOT_SUPPORTED_ERR;
1316 return;
1317 }
darin@apple.coma3c493e2008-03-18 13:47:47 +00001318
ap0289d282006-11-20 18:59:12 +00001319 m_xmlVersion = version;
1320}
1321
1322void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
1323{
1324 if (!implementation()->hasFeature("XML", String())) {
1325 ec = NOT_SUPPORTED_ERR;
1326 return;
1327 }
1328
rwlbuis@webkit.orgac5a7ef2012-04-13 00:58:30 +00001329 m_xmlStandalone = standalone ? Standalone : NotStandalone;
ap0289d282006-11-20 18:59:12 +00001330}
1331
darin@apple.com640fa302008-02-15 05:03:55 +00001332void Document::setDocumentURI(const String& uri)
rwlbuis8643f1f2007-03-07 21:25:16 +00001333{
commit-queue@webkit.org4ef90532012-06-12 18:02:56 +00001334 // This property is read-only from JavaScript, but writable from Objective-C.
abarth@webkit.org761e1002008-06-16 04:43:06 +00001335 m_documentURI = uri;
1336 updateBaseURL();
rwlbuis8643f1f2007-03-07 21:25:16 +00001337}
1338
darin@apple.com640fa302008-02-15 05:03:55 +00001339KURL Document::baseURI() const
rwlbuis8643f1f2007-03-07 21:25:16 +00001340{
darin@apple.com640fa302008-02-15 05:03:55 +00001341 return m_baseURL;
rwlbuis8643f1f2007-03-07 21:25:16 +00001342}
1343
paroga@webkit.orgdb657842011-01-12 01:26:04 +00001344void Document::setContent(const String& content)
1345{
paroga@webkit.orgdb657842011-01-12 01:26:04 +00001346 open();
1347 m_parser->append(content);
abarth@webkit.org3a0207f2011-02-16 00:36:28 +00001348 close();
paroga@webkit.orgdb657842011-01-12 01:26:04 +00001349}
1350
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001351String Document::suggestedMIMEType() const
1352{
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +00001353 if (m_document->isXHTMLDocument())
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001354 return "application/xhtml+xml";
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +00001355 if (m_document->isSVGDocument())
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001356 return "image/svg+xml";
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +00001357 if (m_document->xmlStandalone())
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001358 return "text/xml";
commit-queue@webkit.orgc4534e12012-07-24 00:53:24 +00001359 if (m_document->isHTMLDocument())
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001360 return "text/html";
1361
beidson@apple.com197fbd32011-05-31 22:13:06 +00001362 if (DocumentLoader* documentLoader = loader())
1363 return documentLoader->responseMIMEType();
1364 return String();
abarth@webkit.orga6659fd2011-04-28 22:03:09 +00001365}
1366
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001367// FIXME: We need to discuss the DOM API here at some point. Ideas:
1368// * making it receive a rect as parameter, i.e. nodesFromRect(x, y, w, h);
1369// * making it receive the expading size of each direction separately,
1370// i.e. nodesFromRect(x, y, topSize, rightSize, bottomSize, leftSize);
jchaffraix@webkit.org5083f632012-09-15 01:24:30 +00001371PassRefPtr<NodeList> Document::nodesFromRect(int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent) const
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001372{
1373 // FIXME: Share code between this, elementFromPoint and caretRangeFromPoint.
1374 if (!renderer())
1375 return 0;
1376 Frame* frame = this->frame();
1377 if (!frame)
1378 return 0;
1379 FrameView* frameView = frame->view();
1380 if (!frameView)
1381 return 0;
1382
darin@apple.com0f442a72010-09-18 00:32:24 +00001383 float zoomFactor = frame->pageZoomFactor();
leviw@chromium.org3af17062011-08-18 00:36:48 +00001384 LayoutPoint point = roundedLayoutPoint(FloatPoint(centerX * zoomFactor + view()->scrollX(), centerY * zoomFactor + view()->scrollY()));
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001385
commit-queue@webkit.org3f2c0092012-09-13 05:09:58 +00001386 int type = HitTestRequest::ReadOnly | HitTestRequest::Active;
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001387
1388 // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
commit-queue@webkit.org3f2c0092012-09-13 05:09:58 +00001389 if (ignoreClipping)
1390 type |= HitTestRequest::IgnoreClipping;
1391 else if (!frameView->visibleContentRect().intersects(HitTestResult::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding)))
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001392 return 0;
commit-queue@webkit.org3f2c0092012-09-13 05:09:58 +00001393 if (allowShadowContent)
1394 type |= HitTestRequest::AllowShadowContent;
commit-queue@webkit.org3f2c0092012-09-13 05:09:58 +00001395
1396 HitTestRequest request(type);
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001397
1398 // Passing a zero padding will trigger a rect hit test, however for the purposes of nodesFromRect,
1399 // we special handle this case in order to return a valid NodeList.
tonikitoo@webkit.org6e7483d2010-09-28 02:28:25 +00001400 if (!topPadding && !rightPadding && !bottomPadding && !leftPadding) {
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001401 HitTestResult result(point);
1402 return handleZeroPadding(request, result);
1403 }
1404
allan.jensen@nokia.com4c7e3522012-09-03 14:41:42 +00001405 HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
jchaffraix@webkit.org9dbf6d12012-04-12 16:02:25 +00001406 renderView()->hitTest(request, result);
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001407
1408 return StaticHashSetNodeList::adopt(result.rectBasedTestResult());
1409}
1410
1411PassRefPtr<NodeList> Document::handleZeroPadding(const HitTestRequest& request, HitTestResult& result) const
1412{
jchaffraix@webkit.org9dbf6d12012-04-12 16:02:25 +00001413 renderView()->hitTest(request, result);
tonikitoo@webkit.org81c027d2010-07-29 13:19:43 +00001414
1415 Node* node = result.innerNode();
1416 if (!node)
1417 return 0;
1418
1419 node = node->shadowAncestorNode();
1420 ListHashSet<RefPtr<Node> > list;
1421 list.add(node);
1422 return StaticHashSetNodeList::adopt(list);
1423}
1424
leviw@chromium.org3af17062011-08-18 00:36:48 +00001425static Node* nodeFromPoint(Frame* frame, RenderView* renderView, int x, int y, LayoutPoint* localPoint = 0)
darinb9481ed2006-03-20 02:57:59 +00001426{
weinig@apple.comd2427962009-09-12 19:11:55 +00001427 if (!frame)
1428 return 0;
1429 FrameView* frameView = frame->view();
1430 if (!frameView)
1431 return 0;
darinb9481ed2006-03-20 02:57:59 +00001432
darin@apple.com0f442a72010-09-18 00:32:24 +00001433 float zoomFactor = frame->pageZoomFactor();
eae@chromium.orgb469de32011-02-24 12:31:15 +00001434 IntPoint point = roundedIntPoint(FloatPoint(x * zoomFactor + frameView->scrollX(), y * zoomFactor + frameView->scrollY()));
simon.fraser@apple.com154f13a2009-03-23 18:56:35 +00001435
mrowe@apple.combc939262009-09-15 18:40:11 +00001436 if (!frameView->visibleContentRect().contains(point))
weinig@apple.comd2427962009-09-12 19:11:55 +00001437 return 0;
simon.fraser@apple.com154f13a2009-03-23 18:56:35 +00001438
weinig@apple.comd2427962009-09-12 19:11:55 +00001439 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1440 HitTestResult result(point);
jchaffraix@webkit.org9dbf6d12012-04-12 16:02:25 +00001441 renderView->hitTest(request, result);
darinb9481ed2006-03-20 02:57:59 +00001442
eae@chromium.orgb469de32011-02-24 12:31:15 +00001443 if (localPoint)
1444 *localPoint = result.localPoint();
1445
1446 return result.innerNode();
1447}
1448
1449Element* Document::elementFromPoint(int x, int y) const
1450{
1451 if (!renderer())
1452 return 0;
1453 Node* node = nodeFromPoint(frame(), renderView(), x, y);
1454 while (node && !node->isElementNode())
1455 node = node->parentNode();
1456 if (node)
shinyak@chromium.org42d59fc2012-05-24 03:59:41 +00001457 node = ancestorInThisScope(node);
eae@chromium.orgb469de32011-02-24 12:31:15 +00001458 return static_cast<Element*>(node);
darinb9481ed2006-03-20 02:57:59 +00001459}
1460
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001461PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y)
1462{
1463 if (!renderer())
1464 return 0;
leviw@chromium.org3af17062011-08-18 00:36:48 +00001465 LayoutPoint localPoint;
eae@chromium.orgb469de32011-02-24 12:31:15 +00001466 Node* node = nodeFromPoint(frame(), renderView(), x, y, &localPoint);
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001467 if (!node)
1468 return 0;
1469
shinyak@chromium.org1bc322a2012-05-24 03:45:18 +00001470 Node* shadowAncestorNode = ancestorInThisScope(node);
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001471 if (shadowAncestorNode != node) {
1472 unsigned offset = shadowAncestorNode->nodeIndex();
darin@apple.com601d44b2010-10-15 18:30:37 +00001473 ContainerNode* container = shadowAncestorNode->parentNode();
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001474 return Range::create(this, container, offset, container, offset);
1475 }
1476
1477 RenderObject* renderer = node->renderer();
1478 if (!renderer)
1479 return 0;
eae@chromium.orgb469de32011-02-24 12:31:15 +00001480 VisiblePosition visiblePosition = renderer->positionForPoint(localPoint);
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001481 if (visiblePosition.isNull())
1482 return 0;
1483
commit-queue@webkit.orgc56f5de2011-01-19 09:32:09 +00001484 Position rangeCompliantPosition = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
weinig@apple.com628cb2c2009-09-08 22:02:41 +00001485 return Range::create(this, rangeCompliantPosition, rangeCompliantPosition);
1486}
1487
eric@webkit.org0e917422010-01-07 21:32:13 +00001488/*
1489 * Performs three operations:
1490 * 1. Convert control characters to spaces
1491 * 2. Trim leading and trailing spaces
1492 * 3. Collapse internal whitespace.
1493 */
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001494static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection)
eric@webkit.org0e917422010-01-07 21:32:13 +00001495{
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001496 const String& title = titleWithDirection.string();
eric@webkit.org0e917422010-01-07 21:32:13 +00001497 const UChar* characters = title.characters();
1498 unsigned length = title.length();
1499 unsigned i;
1500
msaboff@apple.comb81ffeb2011-11-16 22:46:31 +00001501 StringBuffer<UChar> buffer(length);
eric@webkit.org0e917422010-01-07 21:32:13 +00001502 unsigned builderIndex = 0;
1503
1504 // Skip leading spaces and leading characters that would convert to spaces
1505 for (i = 0; i < length; ++i) {
1506 UChar c = characters[i];
1507 if (!(c <= 0x20 || c == 0x7F))
1508 break;
1509 }
1510
1511 if (i == length)
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001512 return StringWithDirection();
eric@webkit.org0e917422010-01-07 21:32:13 +00001513
1514 // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
1515 bool previousCharWasWS = false;
1516 for (; i < length; ++i) {
1517 UChar c = characters[i];
1518 if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) {
1519 if (previousCharWasWS)
1520 continue;
1521 buffer[builderIndex++] = ' ';
1522 previousCharWasWS = true;
1523 } else {
1524 buffer[builderIndex++] = c;
1525 previousCharWasWS = false;
1526 }
1527 }
1528
1529 // Strip trailing spaces
1530 while (builderIndex > 0) {
1531 --builderIndex;
1532 if (buffer[builderIndex] != ' ')
1533 break;
1534 }
1535
1536 if (!builderIndex && buffer[builderIndex] == ' ')
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001537 return StringWithDirection();
eric@webkit.org0e917422010-01-07 21:32:13 +00001538
1539 buffer.shrink(builderIndex + 1);
1540
1541 // Replace the backslashes with currency symbols if the encoding requires it.
1542 document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
1543
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001544 return StringWithDirection(String::adopt(buffer), titleWithDirection.direction());
eric@webkit.org0e917422010-01-07 21:32:13 +00001545}
1546
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001547void Document::updateTitle(const StringWithDirection& title)
darinb9481ed2006-03-20 02:57:59 +00001548{
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001549 if (m_rawTitle == title)
1550 return;
1551
1552 m_rawTitle = title;
eric@webkit.org0e917422010-01-07 21:32:13 +00001553 m_title = canonicalizedTitle(this, m_rawTitle);
darin4a244792006-05-05 15:22:33 +00001554 if (Frame* f = frame())
darinc370e7e2006-11-08 05:52:27 +00001555 f->loader()->setTitle(m_title);
darinb9481ed2006-03-20 02:57:59 +00001556}
1557
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001558void Document::setTitle(const String& title)
darinb9481ed2006-03-20 02:57:59 +00001559{
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001560 // Title set by JavaScript -- overrides any title elements.
1561 m_titleSetExplicitly = true;
commit-queue@webkit.org017a7d32011-09-13 03:50:01 +00001562 if (!isHTMLDocument() && !isXHTMLDocument())
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001563 m_titleElement = 0;
1564 else if (!m_titleElement) {
1565 if (HTMLElement* headElement = head()) {
1566 m_titleElement = createElement(titleTag, false);
1567 ExceptionCode ec = 0;
1568 headElement->appendChild(m_titleElement, ec);
1569 ASSERT(!ec);
bdashf45c4e32007-01-24 03:44:47 +00001570 }
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001571 }
1572
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001573 // The DOM API has no method of specifying direction, so assume LTR.
1574 updateTitle(StringWithDirection(title, LTR));
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001575
evan@chromium.org28970be2011-03-30 12:55:45 +00001576 if (m_titleElement) {
1577 ASSERT(m_titleElement->hasTagName(titleTag));
1578 if (m_titleElement->hasTagName(titleTag))
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001579 static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(title);
evan@chromium.org28970be2011-03-30 12:55:45 +00001580 }
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001581}
1582
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001583void Document::setTitleElement(const StringWithDirection& title, Element* titleElement)
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001584{
1585 if (titleElement != m_titleElement) {
bdashfa8c5ec2007-01-23 04:00:54 +00001586 if (m_titleElement || m_titleSetExplicitly)
darinb9481ed2006-03-20 02:57:59 +00001587 // Only allow the first title element to change the title -- others have no effect.
1588 return;
1589 m_titleElement = titleElement;
1590 }
1591
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001592 updateTitle(title);
darinb9481ed2006-03-20 02:57:59 +00001593}
1594
bdashf45c4e32007-01-24 03:44:47 +00001595void Document::removeTitle(Element* titleElement)
darinb9481ed2006-03-20 02:57:59 +00001596{
1597 if (m_titleElement != titleElement)
1598 return;
1599
darinb9481ed2006-03-20 02:57:59 +00001600 m_titleElement = 0;
bdashf45c4e32007-01-24 03:44:47 +00001601 m_titleSetExplicitly = false;
darinb9481ed2006-03-20 02:57:59 +00001602
bdashf45c4e32007-01-24 03:44:47 +00001603 // Update title based on first title element in the head, if one exists.
1604 if (HTMLElement* headElement = head()) {
1605 for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
1606 if (e->hasTagName(titleTag)) {
1607 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001608 setTitleElement(titleElement->textWithDirection(), titleElement);
bdashf45c4e32007-01-24 03:44:47 +00001609 break;
1610 }
1611 }
1612
evan@chromium.org50b7afc2011-03-30 11:21:53 +00001613 if (!m_titleElement)
evan@chromium.orgc3532e92011-03-31 15:17:13 +00001614 updateTitle(StringWithDirection());
darinb9481ed2006-03-20 02:57:59 +00001615}
1616
commit-queue@webkit.org084ff962011-05-09 11:00:47 +00001617#if ENABLE(PAGE_VISIBILITY_API)
1618PageVisibilityState Document::visibilityState() const
1619{
1620 // The visibility of the document is inherited from the visibility of the
1621 // page. If there is no page associated with the document, we will assume
1622 // that the page is visible i.e. invisibility has to be explicitly
1623 // specified by the embedder.
1624 if (!m_frame || !m_frame->page())
1625 return PageVisibilityStateVisible;
1626 return m_frame->page()->visibilityState();
1627}
1628
1629String Document::webkitVisibilityState() const
1630{
tonyg@chromium.org245b8642011-05-09 18:18:54 +00001631 return pageVisibilityStateString(visibilityState());
commit-queue@webkit.org084ff962011-05-09 11:00:47 +00001632}
1633
commit-queue@webkit.orgdcc67412011-06-01 14:11:23 +00001634bool Document::webkitHidden() const
commit-queue@webkit.org084ff962011-05-09 11:00:47 +00001635{
commit-queue@webkit.orgdcc67412011-06-01 14:11:23 +00001636 return visibilityState() != PageVisibilityStateVisible;
commit-queue@webkit.org084ff962011-05-09 11:00:47 +00001637}
1638
1639void Document::dispatchVisibilityStateChangeEvent()
1640{
commit-queue@webkit.orgdcc67412011-06-01 14:11:23 +00001641 dispatchEvent(Event::create(eventNames().webkitvisibilitychangeEvent, false, false));
commit-queue@webkit.org084ff962011-05-09 11:00:47 +00001642}
1643#endif
1644
commit-queue@webkit.org05199e52012-07-26 09:49:52 +00001645#if ENABLE(CSP_NEXT)
1646DOMSecurityPolicy* Document::securityPolicy()
1647{
1648 if (!m_domSecurityPolicy)
1649 m_domSecurityPolicy = DOMSecurityPolicy::create(this);
1650 return m_domSecurityPolicy.get();
1651}
1652#endif
1653
darinb9481ed2006-03-20 02:57:59 +00001654String Document::nodeName() const
1655{
1656 return "#document";
1657}
1658
1659Node::NodeType Document::nodeType() const
1660{
1661 return DOCUMENT_NODE;
1662}
1663
tkent@chromium.org34554872012-06-08 09:53:52 +00001664FormController* Document::formController()
1665{
1666 if (!m_formController)
1667 m_formController = FormController::create();
1668 return m_formController.get();
1669}
1670
1671Vector<String> Document::formElementsState() const
1672{
1673 if (!m_formController)
1674 return Vector<String>();
1675 return m_formController->formElementsState();
1676}
1677
1678void Document::setStateForNewFormElements(const Vector<String>& stateVector)
1679{
1680 if (!stateVector.size() && !m_formController)
1681 return;
1682 formController()->setStateForNewFormElements(stateVector);
1683}
1684
ggaren7c5851a2006-12-12 22:11:18 +00001685FrameView* Document::view() const
1686{
mjs22f8a1a2007-04-29 07:33:46 +00001687 return m_frame ? m_frame->view() : 0;
ggaren7c5851a2006-12-12 22:11:18 +00001688}
1689
ggaren7c5851a2006-12-12 22:11:18 +00001690Page* Document::page() const
1691{
ggaren6ad6e762007-05-25 09:13:32 +00001692 return m_frame ? m_frame->page() : 0;
1693}
1694
1695Settings* Document::settings() const
1696{
1697 return m_frame ? m_frame->settings() : 0;
ggaren7c5851a2006-12-12 22:11:18 +00001698}
1699
darinb9481ed2006-03-20 02:57:59 +00001700PassRefPtr<Range> Document::createRange()
1701{
darin@apple.comb7bf13a2008-03-11 23:43:12 +00001702 return Range::create(this);
darinb9481ed2006-03-20 02:57:59 +00001703}
1704
1705PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow,
darin@apple.come4f9a662008-02-08 10:35:20 +00001706 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00001707{
1708 if (!root) {
1709 ec = NOT_SUPPORTED_ERR;
1710 return 0;
1711 }
andersca@apple.com0f509b12008-06-04 21:12:16 +00001712 return NodeIterator::create(root, whatToShow, filter, expandEntityReferences);
darinb9481ed2006-03-20 02:57:59 +00001713}
1714
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00001715PassRefPtr<TreeWalker> Document::createTreeWalker(Node* root, unsigned whatToShow,
darin@apple.come4f9a662008-02-08 10:35:20 +00001716 PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00001717{
1718 if (!root) {
1719 ec = NOT_SUPPORTED_ERR;
1720 return 0;
1721 }
andersca@apple.com0f509b12008-06-04 21:12:16 +00001722 return TreeWalker::create(root, whatToShow, filter, expandEntityReferences);
darinb9481ed2006-03-20 02:57:59 +00001723}
1724
hyatt@apple.com9e924282010-08-26 19:33:40 +00001725void Document::scheduleForcedStyleRecalc()
1726{
1727 m_pendingStyleRecalcShouldForce = true;
1728 scheduleStyleRecalc();
1729}
1730
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001731void Document::scheduleStyleRecalc()
darinb9481ed2006-03-20 02:57:59 +00001732{
eric@webkit.org7e897f72012-05-24 01:07:22 +00001733 if (shouldDisplaySeamlesslyWithParent()) {
1734 // When we're seamless, our parent document manages our style recalcs.
1735 ownerElement()->setNeedsStyleRecalc();
1736 ownerElement()->document()->scheduleStyleRecalc();
1737 return;
1738 }
eric@webkit.org981501e2012-05-10 22:11:57 +00001739
hyatt@apple.com094f41b2009-04-13 17:14:44 +00001740 if (m_styleRecalcTimer.isActive() || inPageCache())
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001741 return;
darinb9481ed2006-03-20 02:57:59 +00001742
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00001743 ASSERT(childNeedsStyleRecalc() || m_pendingStyleRecalcShouldForce);
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001744
1745 if (!documentsThatNeedStyleRecalc)
1746 documentsThatNeedStyleRecalc = new HashSet<Document*>;
1747 documentsThatNeedStyleRecalc->add(this);
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001748
1749 // FIXME: Why on earth is this here? This is clearly misplaced.
rolandsteiner@chromium.orga3cbe772011-04-04 22:25:18 +00001750 invalidateAccessKeyMap();
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001751
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001752 m_styleRecalcTimer.startOneShot(0);
vsevik@chromium.orgd0f79f12011-07-28 15:13:34 +00001753
1754 InspectorInstrumentation::didScheduleStyleRecalculation(this);
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001755}
1756
1757void Document::unscheduleStyleRecalc()
1758{
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001759 ASSERT(!childNeedsStyleRecalc());
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001760
1761 if (documentsThatNeedStyleRecalc)
1762 documentsThatNeedStyleRecalc->remove(this);
1763
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001764 m_styleRecalcTimer.stop();
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +00001765 m_pendingStyleRecalcShouldForce = false;
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001766}
1767
antti@apple.com52bdb212012-09-28 03:51:25 +00001768bool Document::hasPendingStyleRecalc() const
mitz@apple.com543c3002010-11-16 22:08:26 +00001769{
1770 return m_styleRecalcTimer.isActive() && !m_inStyleRecalc;
1771}
1772
antti@apple.com52bdb212012-09-28 03:51:25 +00001773bool Document::hasPendingForcedStyleRecalc() const
1774{
1775 return m_styleRecalcTimer.isActive() && m_pendingStyleRecalcShouldForce;
1776}
1777
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001778void Document::styleRecalcTimerFired(Timer<Document>*)
1779{
1780 updateStyleIfNeeded();
darinb9481ed2006-03-20 02:57:59 +00001781}
1782
ojan@chromium.orge4d44e12009-07-27 22:45:37 +00001783bool Document::childNeedsAndNotInStyleRecalc()
1784{
1785 return childNeedsStyleRecalc() && !m_inStyleRecalc;
1786}
1787
darinb9481ed2006-03-20 02:57:59 +00001788void Document::recalcStyle(StyleChange change)
1789{
antti6e917c32007-08-06 02:05:15 +00001790 // we should not enter style recalc while painting
rafael.lobo@openbossa.org4687db82012-08-30 03:48:29 +00001791 ASSERT(!view() || !view()->isPainting());
1792 if (view() && view()->isPainting())
antti6e917c32007-08-06 02:05:15 +00001793 return;
antti6e917c32007-08-06 02:05:15 +00001794
darinb9481ed2006-03-20 02:57:59 +00001795 if (m_inStyleRecalc)
1796 return; // Guard against re-entrancy. -dwh
eric@webkit.org981501e2012-05-10 22:11:57 +00001797
eric@webkit.org7e897f72012-05-24 01:07:22 +00001798 // FIXME: We should update style on our ancestor chain before proceeding (especially for seamless),
1799 // however doing so currently causes several tests to crash, as Frame::setDocument calls Document::attach
1800 // before setting the DOMWindow on the Frame, or the SecurityOrigin on the document. The attach, in turn
1801 // resolves style (here) and then when we resolve style on the parent chain, we may end up
1802 // re-attaching our containing iframe, which when asked HTMLFrameElementBase::isURLAllowed
1803 // hits a null-dereference due to security code always assuming the document has a SecurityOrigin.
eric@webkit.org981501e2012-05-10 22:11:57 +00001804
antti@apple.come5a88a72012-09-24 22:14:47 +00001805 if (m_styleSheetCollection->needsUpdateActiveStylesheetsOnStyleRecalc())
1806 m_styleSheetCollection->updateActiveStyleSheets(DocumentStyleSheetCollection::FullUpdate);
commit-queue@webkit.org4c49a662011-01-02 22:27:10 +00001807
podivilov@chromium.orgb6cd0252010-10-07 09:43:02 +00001808 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willRecalculateStyle(this);
eric@webkit.org80bd7d62009-09-08 17:55:32 +00001809
antti@apple.com384e66f2012-05-23 17:17:43 +00001810 if (m_elemSheet && m_elemSheet->contents()->usesRemUnits())
antti@apple.come5a88a72012-09-24 22:14:47 +00001811 m_styleSheetCollection->setUsesRemUnit(true);
antti@apple.com87bb1832012-04-13 21:23:13 +00001812
darinb9481ed2006-03-20 02:57:59 +00001813 m_inStyleRecalc = true;
mitz@apple.com8476cbd2007-11-23 06:04:36 +00001814 suspendPostAttachCallbacks();
rniwa@webkit.org04ec2982012-09-24 20:34:35 +00001815 {
1816 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1817
1818 RefPtr<FrameView> frameView = view();
1819 if (frameView) {
1820 frameView->pauseScheduledEvents();
1821 frameView->beginDeferredRepaints();
1822 }
1823
1824 ASSERT(!renderer() || renderArena());
1825 if (!renderer() || !renderArena())
1826 goto bailOut;
1827
1828 if (m_pendingStyleRecalcShouldForce)
1829 change = Force;
1830
1831 // Recalculating the root style (on the document) is not needed in the common case.
1832 if ((change == Force) || (shouldDisplaySeamlesslyWithParent() && (change >= Inherit))) {
1833 // style selector may set this again during recalc
1834 m_hasNodesWithPlaceholderStyle = false;
1835
1836 RefPtr<RenderStyle> documentStyle = StyleResolver::styleForDocument(this, m_styleResolver ? m_styleResolver->fontSelector() : 0);
1837 StyleChange ch = Node::diff(documentStyle.get(), renderer()->style(), this);
1838 if (ch != NoChange)
1839 renderer()->setStyle(documentStyle.release());
1840 }
1841
1842 for (Node* n = firstChild(); n; n = n->nextSibling()) {
1843 if (!n->isElementNode())
1844 continue;
1845 Element* element = static_cast<Element*>(n);
1846 if (change >= Inherit || element->childNeedsStyleRecalc() || element->needsStyleRecalc())
1847 element->recalcStyle(change);
1848 }
1849
1850 #if USE(ACCELERATED_COMPOSITING)
1851 if (view()) {
1852 bool layoutPending = view()->layoutPending() || renderer()->needsLayout();
1853 // If we didn't update compositing layers because of layout(), we need to do so here.
1854 if (!layoutPending)
1855 view()->updateCompositingLayersAfterStyleChange();
1856 }
1857 #endif
1858
1859 bailOut:
1860 clearNeedsStyleRecalc();
1861 clearChildNeedsStyleRecalc();
1862 unscheduleStyleRecalc();
1863
1864 m_inStyleRecalc = false;
1865
1866 // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
1867 if (m_styleResolver)
antti@apple.come5a88a72012-09-24 22:14:47 +00001868 m_styleSheetCollection->resetCSSFeatureFlags();
rniwa@webkit.org04ec2982012-09-24 20:34:35 +00001869
1870 if (frameView) {
1871 frameView->resumeScheduledEvents();
1872 frameView->endDeferredRepaints();
1873 }
antti@apple.com587e9cf2011-04-05 22:29:33 +00001874 }
mitz@apple.com8476cbd2007-11-23 06:04:36 +00001875 resumePostAttachCallbacks();
mitz@apple.com8a089a42009-03-01 19:02:08 +00001876
ggarena57755c2007-07-09 21:08:10 +00001877 // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
darinb9481ed2006-03-20 02:57:59 +00001878 if (m_closeAfterStyleRecalc) {
1879 m_closeAfterStyleRecalc = false;
1880 implicitClose();
1881 }
commit-queue@webkit.org4c49a662011-01-02 22:27:10 +00001882
podivilov@chromium.orgc5dc5a72010-10-08 16:39:57 +00001883 InspectorInstrumentation::didRecalculateStyle(cookie);
darinb9481ed2006-03-20 02:57:59 +00001884}
1885
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001886void Document::updateStyleIfNeeded()
darinb9481ed2006-03-20 02:57:59 +00001887{
rniwa@webkit.orgcf0fea92010-11-05 22:47:59 +00001888 ASSERT(isMainThread());
simon.fraser@apple.com64487f92010-08-19 17:19:40 +00001889 ASSERT(!view() || (!view()->isInLayout() && !view()->isPainting()));
1890
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00001891 if ((!m_pendingStyleRecalcShouldForce && !childNeedsStyleRecalc()) || inPageCache())
cmarrin@apple.com3ec14ff2009-01-24 15:10:06 +00001892 return;
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00001893
simon.fraser@apple.comdbb80872012-05-22 21:17:44 +00001894 AnimationUpdateBlock animationUpdateBlock(m_frame ? m_frame->animation() : 0);
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +00001895 recalcStyle(NoChange);
darinb9481ed2006-03-20 02:57:59 +00001896}
1897
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001898void Document::updateStyleForAllDocuments()
darinb9481ed2006-03-20 02:57:59 +00001899{
rniwa@webkit.orgcf0fea92010-11-05 22:47:59 +00001900 ASSERT(isMainThread());
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001901 if (!documentsThatNeedStyleRecalc)
darinb9481ed2006-03-20 02:57:59 +00001902 return;
1903
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001904 while (documentsThatNeedStyleRecalc->size()) {
1905 HashSet<Document*>::iterator it = documentsThatNeedStyleRecalc->begin();
andersca@apple.comf1fef132008-06-23 16:24:24 +00001906 Document* doc = *it;
hyatt@apple.comdcf36332009-04-10 03:15:05 +00001907 documentsThatNeedStyleRecalc->remove(doc);
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001908 doc->updateStyleIfNeeded();
darinb9481ed2006-03-20 02:57:59 +00001909 }
1910}
1911
1912void Document::updateLayout()
1913{
rniwa@webkit.orgcf0fea92010-11-05 22:47:59 +00001914 ASSERT(isMainThread());
darin52c807982007-04-19 00:33:29 +00001915 if (Element* oe = ownerElement())
1916 oe->document()->updateLayout();
1917
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00001918 updateStyleIfNeeded();
darinb9481ed2006-03-20 02:57:59 +00001919
slewis@apple.com9b67c992010-01-08 01:56:08 +00001920 // Only do a layout if changes have occurred that make it necessary.
mjs22f8a1a2007-04-29 07:33:46 +00001921 FrameView* v = view();
slewis@apple.com9b67c992010-01-08 01:56:08 +00001922 if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
mjs22f8a1a2007-04-29 07:33:46 +00001923 v->layout();
darinb9481ed2006-03-20 02:57:59 +00001924}
1925
1926// FIXME: This is a bad idea and needs to be removed eventually.
1927// Other browsers load stylesheets before they continue parsing the web page.
1928// Since we don't, we can run JavaScript code that needs answers before the
1929// stylesheets are loaded. Doing a layout ignoring the pending stylesheets
1930// lets us get reasonable answers. The long term solution to this problem is
1931// to instead suspend JavaScript execution.
1932void Document::updateLayoutIgnorePendingStylesheets()
1933{
1934 bool oldIgnore = m_ignorePendingStylesheets;
1935
1936 if (!haveStylesheetsLoaded()) {
1937 m_ignorePendingStylesheets = true;
hyatta9c6a342006-09-02 01:43:36 +00001938 // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be
1939 // dangerous to try to stop it a second time, after page content has already been loaded and displayed
1940 // with accurate style information. (Our suppression involves blanking the whole page at the
1941 // moment. If it were more refined, we might be able to do something better.)
1942 // It's worth noting though that this entire method is a hack, since what we really want to do is
1943 // suspend JS instead of doing a layout with inaccurate information.
kling@webkit.org156604c2011-12-16 08:51:18 +00001944 HTMLElement* bodyElement = body();
1945 if (bodyElement && !bodyElement->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
hyatta9c6a342006-09-02 01:43:36 +00001946 m_pendingSheetLayout = DidLayoutWithPendingSheets;
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00001947 styleResolverChanged(RecalcStyleImmediately);
anttifa58db352007-08-29 22:46:41 +00001948 } else if (m_hasNodesWithPlaceholderStyle)
1949 // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes
1950 // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive
dbates@webkit.orgef42d382010-01-25 19:20:06 +00001951 // but here we need up-to-date style immediately.
anttifa58db352007-08-29 22:46:41 +00001952 recalcStyle(Force);
darinb9481ed2006-03-20 02:57:59 +00001953 }
1954
1955 updateLayout();
1956
1957 m_ignorePendingStylesheets = oldIgnore;
1958}
1959
mitz@apple.comcd786b22010-02-19 00:19:48 +00001960PassRefPtr<RenderStyle> Document::styleForElementIgnoringPendingStylesheets(Element* element)
1961{
1962 ASSERT_ARG(element, element->document() == this);
1963
1964 bool oldIgnore = m_ignorePendingStylesheets;
1965 m_ignorePendingStylesheets = true;
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00001966 RefPtr<RenderStyle> style = styleResolver()->styleForElement(element, element->parentNode() ? element->parentNode()->computedStyle() : 0);
mitz@apple.comcd786b22010-02-19 00:19:48 +00001967 m_ignorePendingStylesheets = oldIgnore;
1968 return style.release();
1969}
1970
yuzo@google.comb1f14f82010-06-16 03:23:12 +00001971PassRefPtr<RenderStyle> Document::styleForPage(int pageIndex)
1972{
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00001973 RefPtr<RenderStyle> style = styleResolver()->styleForPage(pageIndex);
yuzo@google.comb1f14f82010-06-16 03:23:12 +00001974 return style.release();
1975}
1976
schenney@chromium.orgfc27bcb2012-10-02 13:03:18 +00001977void Document::registerCustomFont(PassRefPtr<FontData> fontData)
commit-queue@webkit.orgdef1a492012-09-07 22:58:56 +00001978{
1979 m_customFonts.append(fontData);
1980}
1981
1982void Document::deleteCustomFonts()
1983{
1984 size_t size = m_customFonts.size();
1985 for (size_t i = 0; i < size; ++i)
1986 GlyphPageTreeNode::pruneTreeCustomFontData(m_customFonts[i].get());
1987
1988 m_customFonts.clear();
1989}
1990
yuzo@google.com164cf382010-06-23 07:30:04 +00001991bool Document::isPageBoxVisible(int pageIndex)
1992{
1993 RefPtr<RenderStyle> style = styleForPage(pageIndex);
1994 return style->visibility() != HIDDEN; // display property doesn't apply to @page.
1995}
1996
yuzo@google.com0170f202010-06-28 01:59:51 +00001997void Document::pageSizeAndMarginsInPixels(int pageIndex, IntSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
yuzo@google.com164cf382010-06-23 07:30:04 +00001998{
1999 RefPtr<RenderStyle> style = styleForPage(pageIndex);
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +00002000 RenderView* view = renderView();
yuzo@google.com164cf382010-06-23 07:30:04 +00002001
yuzo@google.com0170f202010-06-28 01:59:51 +00002002 int width = pageSize.width();
2003 int height = pageSize.height();
2004 switch (style->pageSizeType()) {
2005 case PAGE_SIZE_AUTO:
2006 break;
2007 case PAGE_SIZE_AUTO_LANDSCAPE:
2008 if (width < height)
2009 std::swap(width, height);
2010 break;
2011 case PAGE_SIZE_AUTO_PORTRAIT:
2012 if (width > height)
2013 std::swap(width, height);
2014 break;
2015 case PAGE_SIZE_RESOLVED: {
2016 LengthSize size = style->pageSize();
2017 ASSERT(size.width().isFixed());
2018 ASSERT(size.height().isFixed());
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +00002019 width = valueForLength(size.width(), 0, view);
2020 height = valueForLength(size.height(), 0, view);
yuzo@google.com0170f202010-06-28 01:59:51 +00002021 break;
2022 }
2023 default:
2024 ASSERT_NOT_REACHED();
2025 }
2026 pageSize = IntSize(width, height);
yuzo@google.com164cf382010-06-23 07:30:04 +00002027
yuzo@google.com0170f202010-06-28 01:59:51 +00002028 // The percentage is calculated with respect to the width even for margin top and bottom.
2029 // http://www.w3.org/TR/CSS2/box.html#margin-properties
leviw@chromium.orgf5ba1872012-04-13 04:19:42 +00002030 marginTop = style->marginTop().isAuto() ? marginTop : intValueForLength(style->marginTop(), width, view);
2031 marginRight = style->marginRight().isAuto() ? marginRight : intValueForLength(style->marginRight(), width, view);
2032 marginBottom = style->marginBottom().isAuto() ? marginBottom : intValueForLength(style->marginBottom(), width, view);
2033 marginLeft = style->marginLeft().isAuto() ? marginLeft : intValueForLength(style->marginLeft(), width, view);
yuzo@google.com164cf382010-06-23 07:30:04 +00002034}
2035
haraken@chromium.orgabf5d022012-06-28 06:29:27 +00002036void Document::setDocumentRareData(NodeRareData* rareData)
2037{
2038 m_documentRareData = rareData;
2039}
2040
japhet@chromium.org0d6b1de2011-05-25 18:51:27 +00002041void Document::setIsViewSource(bool isViewSource)
2042{
2043 m_isViewSource = isViewSource;
2044 if (!m_isViewSource)
2045 return;
2046
abarth@webkit.org435c7592011-11-18 04:58:44 +00002047 setSecurityOrigin(SecurityOrigin::createUnique());
abarth@webkit.orgd19503e2012-08-09 23:59:52 +00002048 didUpdateSecurityOrigin();
japhet@chromium.org0d6b1de2011-05-25 18:51:27 +00002049}
2050
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00002051void Document::createStyleResolver()
hyatt@apple.com0880de12010-01-28 17:47:30 +00002052{
2053 bool matchAuthorAndUserStyles = true;
2054 if (Settings* docSettings = settings())
2055 matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled();
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00002056 m_styleResolver = adoptPtr(new StyleResolver(this, matchAuthorAndUserStyles));
antti@apple.come5a88a72012-09-24 22:14:47 +00002057 m_styleSheetCollection->combineCSSFeatureFlags();
hyatt@apple.com0880de12010-01-28 17:47:30 +00002058}
antti@apple.com846f7b32012-03-27 12:40:38 +00002059
antti@apple.come5a88a72012-09-24 22:14:47 +00002060void Document::clearStyleResolver()
antti@apple.com3f4f37b2012-01-09 14:59:57 +00002061{
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00002062 m_styleResolver.clear();
antti@apple.com3f4f37b2012-01-09 14:59:57 +00002063}
hyatt@apple.com0880de12010-01-28 17:47:30 +00002064
darinb9481ed2006-03-20 02:57:59 +00002065void Document::attach()
2066{
ggarenf9f32ae2007-03-26 20:08:53 +00002067 ASSERT(!attached());
2068 ASSERT(!m_inPageCache);
commit-queue@webkit.orge45033b2011-09-27 17:29:46 +00002069 ASSERT(!m_axObjectCache || this != topDocument());
darinb9481ed2006-03-20 02:57:59 +00002070
2071 if (!m_renderArena)
levin@chromium.org5af8b192011-04-26 17:16:27 +00002072 m_renderArena = adoptPtr(new RenderArena);
darinb9481ed2006-03-20 02:57:59 +00002073
2074 // Create the rendering tree
abarth@webkit.org3e035352009-12-04 05:54:58 +00002075 setRenderer(new (m_renderArena.get()) RenderView(this, view()));
simon.fraser@apple.com8f9c77b2009-02-06 17:05:07 +00002076#if USE(ACCELERATED_COMPOSITING)
2077 renderView()->didMoveOnscreen();
2078#endif
darinb9481ed2006-03-20 02:57:59 +00002079
2080 recalcStyle(Force);
2081
2082 RenderObject* render = renderer();
2083 setRenderer(0);
2084
hayato@chromium.org81596e42012-02-02 04:21:29 +00002085 ContainerNode::attach();
darinb9481ed2006-03-20 02:57:59 +00002086
2087 setRenderer(render);
2088}
2089
darinb9481ed2006-03-20 02:57:59 +00002090void Document::detach()
2091{
darin47829102007-09-06 19:39:32 +00002092 ASSERT(attached());
2093 ASSERT(!m_inPageCache);
2094
scheib@chromium.orgfd0b8a92012-07-13 20:37:50 +00002095#if ENABLE(POINTER_LOCK)
2096 if (page())
2097 page()->pointerLockController()->documentDetached(this);
2098#endif
2099
commit-queue@webkit.orge45033b2011-09-27 17:29:46 +00002100 if (this == topDocument())
2101 clearAXObjectCache();
2102
oliver@apple.com94408062008-12-11 02:14:04 +00002103 stopActiveDOMObjects();
dimich@chromium.org34a3c442011-08-30 17:35:52 +00002104 m_eventQueue->close();
commit-queue@webkit.org49314b92011-09-20 00:19:02 +00002105#if ENABLE(FULLSCREEN_API)
2106 m_fullScreenChangeEventTargetQueue.clear();
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00002107 m_fullScreenErrorEventTargetQueue.clear();
commit-queue@webkit.org49314b92011-09-20 00:19:02 +00002108#endif
zmo@google.com83f778b2011-03-17 23:26:27 +00002109
2110#if ENABLE(REQUEST_ANIMATION_FRAME)
2111 // FIXME: consider using ActiveDOMObject.
jamesr@google.coma5d3c9e2011-12-09 01:33:41 +00002112 if (m_scriptedAnimationController)
2113 m_scriptedAnimationController->clearDocumentPointer();
2114 m_scriptedAnimationController.clear();
zmo@google.com83f778b2011-03-17 23:26:27 +00002115#endif
2116
darinb9481ed2006-03-20 02:57:59 +00002117 RenderObject* render = renderer();
2118
simon.fraser@apple.combd618dd2009-02-19 19:20:33 +00002119 documentWillBecomeInactive();
atwilson@chromium.orge57cf262009-08-12 01:05:22 +00002120
2121#if ENABLE(SHARED_WORKERS)
2122 SharedWorkerRepository::documentDetached(this);
2123#endif
2124
levin@chromium.orgb7428332009-06-22 17:20:03 +00002125 if (m_frame) {
2126 FrameView* view = m_frame->view();
2127 if (view)
2128 view->detachCustomScrollbars();
eric@webkit.org19e68c52010-01-29 17:56:44 +00002129
levin@chromium.orgb7428332009-06-22 17:20:03 +00002130 }
2131
darinb9481ed2006-03-20 02:57:59 +00002132 // indicate destruction mode, i.e. attached() but renderer == 0
2133 setRenderer(0);
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00002134
2135#if ENABLE(FULLSCREEN_API)
2136 if (m_fullScreenRenderer)
2137 setFullScreenRenderer(0);
2138#endif
darin@apple.comc4dab5d2009-03-17 17:02:19 +00002139
darinb9481ed2006-03-20 02:57:59 +00002140 m_hoverNode = 0;
ggaren03a0f872006-12-15 03:43:51 +00002141 m_focusedNode = 0;
darinb9481ed2006-03-20 02:57:59 +00002142 m_activeNode = 0;
2143
hayato@chromium.org81596e42012-02-02 04:21:29 +00002144 ContainerNode::detach();
darinb9481ed2006-03-20 02:57:59 +00002145
hyatt@apple.comdcf36332009-04-10 03:15:05 +00002146 unscheduleStyleRecalc();
2147
darinb9481ed2006-03-20 02:57:59 +00002148 if (render)
2149 render->destroy();
abarth@webkit.org23ea90a2012-08-14 19:47:59 +00002150
eric@webkit.orge0a51622008-06-26 22:45:47 +00002151 // This is required, as our Frame might delete itself as soon as it detaches
dbates@webkit.orgef42d382010-01-25 19:20:06 +00002152 // us. However, this violates Node::detach() semantics, as it's never
darin@apple.com4cd1b242009-03-27 23:37:46 +00002153 // possible to re-attach. Eventually Document::detach() should be renamed,
2154 // or this setting of the frame to 0 could be made explicit in each of the
2155 // callers of Document::detach().
2156 m_frame = 0;
abarth@webkit.org3e035352009-12-04 05:54:58 +00002157 m_renderArena.clear();
darinb9481ed2006-03-20 02:57:59 +00002158}
2159
jberlin@webkit.orga4facf22012-05-10 02:00:38 +00002160void Document::prepareForDestruction()
2161{
morrita@google.com1b44b4d2012-05-10 11:37:09 +00002162 disconnectDescendantFrames();
jberlin@webkit.orga4facf22012-05-10 02:00:38 +00002163 if (DOMWindow* window = this->domWindow())
2164 window->willDetachDocumentFromFrame();
2165 detach();
2166}
2167
ggaren@apple.combc6ef282009-04-13 19:43:47 +00002168void Document::removeAllEventListeners()
darinb9481ed2006-03-20 02:57:59 +00002169{
ggaren@apple.com521f64b2009-09-24 05:53:23 +00002170 EventTarget::removeAllEventListeners();
2171
ggaren@apple.combc6ef282009-04-13 19:43:47 +00002172 if (DOMWindow* domWindow = this->domWindow())
2173 domWindow->removeAllEventListeners();
ggaren@apple.com521f64b2009-09-24 05:53:23 +00002174 for (Node* node = firstChild(); node; node = node->traverseNextNode())
weinig@apple.comb9d2ac22009-02-05 20:35:53 +00002175 node->removeAllEventListeners();
darinb9481ed2006-03-20 02:57:59 +00002176}
2177
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +00002178void Document::suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension why)
2179{
2180 ScriptExecutionContext::suspendActiveDOMObjects(why);
2181
2182#if ENABLE(DEVICE_ORIENTATION)
2183 if (!page())
2184 return;
2185
commit-queue@webkit.org335a9d82012-02-13 01:18:28 +00002186 if (DeviceMotionController* controller = DeviceMotionController::from(page()))
2187 controller->suspendEventsForAllListeners(domWindow());
2188 if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
2189 controller->suspendEventsForAllListeners(domWindow());
2190
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +00002191#endif
2192}
2193
2194void Document::resumeActiveDOMObjects()
2195{
2196 ScriptExecutionContext::resumeActiveDOMObjects();
2197
2198#if ENABLE(DEVICE_ORIENTATION)
2199 if (!page())
2200 return;
2201
commit-queue@webkit.org335a9d82012-02-13 01:18:28 +00002202 if (DeviceMotionController* controller = DeviceMotionController::from(page()))
2203 controller->resumeEventsForAllListeners(domWindow());
2204 if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
2205 controller->resumeEventsForAllListeners(domWindow());
kenneth@webkit.orgae65fe32011-10-26 14:56:09 +00002206#endif
2207}
2208
hyatt@apple.comee163942009-01-23 21:25:32 +00002209RenderView* Document::renderView() const
2210{
weinig@apple.come2da6292009-01-30 21:57:37 +00002211 return toRenderView(renderer());
hyatt@apple.comee163942009-01-23 21:25:32 +00002212}
2213
harrison@apple.com7954df22008-03-12 16:16:40 +00002214void Document::clearAXObjectCache()
2215{
2216 // clear cache in top document
2217 if (m_axObjectCache) {
inferno@chromium.org22417bf2010-11-30 23:21:15 +00002218 // Clear the cache member variable before calling delete because attempts
2219 // are made to access it during destruction.
2220 AXObjectCache* axObjectCache = m_axObjectCache;
harrison@apple.com7954df22008-03-12 16:16:40 +00002221 m_axObjectCache = 0;
inferno@chromium.org22417bf2010-11-30 23:21:15 +00002222 delete axObjectCache;
harrison@apple.com7954df22008-03-12 16:16:40 +00002223 return;
2224 }
2225
2226 // ask the top-level document to clear its cache
2227 Document* doc = topDocument();
2228 if (doc != this)
2229 doc->clearAXObjectCache();
2230}
2231
cfleizach@apple.comc6d72ec2010-09-28 17:59:32 +00002232bool Document::axObjectCacheExists() const
2233{
2234 if (m_axObjectCache)
2235 return true;
2236
2237 Document* doc = topDocument();
2238 if (doc != this)
2239 return doc->axObjectCacheExists();
2240
2241 return false;
2242}
2243
darine775cf72006-07-09 22:48:56 +00002244AXObjectCache* Document::axObjectCache() const
darinb9481ed2006-03-20 02:57:59 +00002245{
darine775cf72006-07-09 22:48:56 +00002246 // The only document that actually has a AXObjectCache is the top-level
darinb9481ed2006-03-20 02:57:59 +00002247 // document. This is because we need to be able to get from any WebCoreAXObject
2248 // to any other WebCoreAXObject on the same page. Using a single cache allows
2249 // lookups across nested webareas (i.e. multiple documents).
2250
darine775cf72006-07-09 22:48:56 +00002251 if (m_axObjectCache) {
darinb9481ed2006-03-20 02:57:59 +00002252 // return already known top-level cache
2253 if (!ownerElement())
darine775cf72006-07-09 22:48:56 +00002254 return m_axObjectCache;
darinb9481ed2006-03-20 02:57:59 +00002255
2256 // In some pages with frames, the cache is created before the sub-webarea is
2257 // inserted into the tree. Here, we catch that case and just toss the old
2258 // cache and start over.
harrison@apple.com7954df22008-03-12 16:16:40 +00002259 // NOTE: This recovery may no longer be needed. I have been unable to trigger
2260 // it again. See rdar://5794454
2261 // FIXME: Can this be fixed when inserting the subframe instead of now?
2262 // FIXME: If this function was called to get the cache in order to remove
2263 // an AXObject, we are now deleting the cache as a whole and returning a
2264 // new empty cache that does not contain the AXObject! That should actually
2265 // be OK. I am concerned about other cases like this where accessing the
2266 // cache blows away the AXObject being operated on.
darine775cf72006-07-09 22:48:56 +00002267 delete m_axObjectCache;
2268 m_axObjectCache = 0;
darinb9481ed2006-03-20 02:57:59 +00002269 }
2270
2271 // ask the top-level document for its cache
darin4e217c02006-03-24 07:07:34 +00002272 Document* doc = topDocument();
darinb9481ed2006-03-20 02:57:59 +00002273 if (doc != this)
darine775cf72006-07-09 22:48:56 +00002274 return doc->axObjectCache();
darinb9481ed2006-03-20 02:57:59 +00002275
2276 // this is the top-level document, so install a new cache
cfleizach@apple.comaa504102011-01-05 01:07:44 +00002277 m_axObjectCache = new AXObjectCache(this);
darine775cf72006-07-09 22:48:56 +00002278 return m_axObjectCache;
darinb9481ed2006-03-20 02:57:59 +00002279}
2280
2281void Document::setVisuallyOrdered()
2282{
hyatt@apple.com0880de12010-01-28 17:47:30 +00002283 m_visuallyOrdered = true;
darinb9481ed2006-03-20 02:57:59 +00002284 if (renderer())
macpherson@chromium.org258babf2011-06-10 06:20:58 +00002285 renderer()->style()->setRTLOrdering(VisualOrder);
darinb9481ed2006-03-20 02:57:59 +00002286}
2287
eric@webkit.org0cea84c2010-08-19 19:32:02 +00002288PassRefPtr<DocumentParser> Document::createParser()
darinb9481ed2006-03-20 02:57:59 +00002289{
mjs22f8a1a2007-04-29 07:33:46 +00002290 // FIXME: this should probably pass the frame instead
jpfau@apple.come854e5d2011-07-08 19:31:34 +00002291#if ENABLE(NEW_XML)
2292 return NewXMLDocumentParser::create(this);
2293#else
eric@webkit.org0cea84c2010-08-19 19:32:02 +00002294 return XMLDocumentParser::create(this, view());
jpfau@apple.come854e5d2011-07-08 19:31:34 +00002295#endif
darinb9481ed2006-03-20 02:57:59 +00002296}
2297
eric@webkit.orge37f5952010-06-28 07:56:10 +00002298ScriptableDocumentParser* Document::scriptableDocumentParser() const
2299{
2300 return parser() ? parser()->asScriptableDocumentParser() : 0;
2301}
2302
abarth@webkit.orgbf2c13a2008-06-12 06:41:53 +00002303void Document::open(Document* ownerDocument)
darinb9481ed2006-03-20 02:57:59 +00002304{
abarth@webkit.orgbf2c13a2008-06-12 06:41:53 +00002305 if (ownerDocument) {
2306 setURL(ownerDocument->url());
abarth@webkit.orgbf2c13a2008-06-12 06:41:53 +00002307 m_cookieURL = ownerDocument->cookieURL();
abarth@webkit.org51ad70c2011-11-18 00:20:41 +00002308 setSecurityOrigin(ownerDocument->securityOrigin());
aliceli14bd01002006-08-28 20:43:36 +00002309 }
aliceli14bd01002006-08-28 20:43:36 +00002310
andersca07ff2212007-07-24 03:09:32 +00002311 if (m_frame) {
tonyg@chromium.org9ccc4f32011-03-01 00:54:55 +00002312 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) {
2313 if (parser->isParsing()) {
2314 // FIXME: HTML5 doesn't tell us to check this, it might not be correct.
2315 if (parser->isExecutingScript())
2316 return;
2317
2318 if (!parser->wasCreatedByScript() && parser->hasInsertionPoint())
2319 return;
2320 }
2321 }
eric@webkit.orge37f5952010-06-28 07:56:10 +00002322
andersca07ff2212007-07-24 03:09:32 +00002323 if (m_frame->loader()->state() == FrameStateProvisional)
2324 m_frame->loader()->stopAllLoaders();
2325 }
abarth@webkit.org4c4bee02009-06-19 18:25:42 +00002326
commit-queue@webkit.org53b27b52010-10-13 23:10:56 +00002327 removeAllEventListeners();
darinb9481ed2006-03-20 02:57:59 +00002328 implicitOpen();
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002329 if (ScriptableDocumentParser* parser = scriptableDocumentParser())
2330 parser->setWasCreatedByScript(true);
darinb9481ed2006-03-20 02:57:59 +00002331
eric@webkit.org871c3a72009-10-13 20:27:04 +00002332 if (DOMWindow* domWindow = this->domWindow())
2333 domWindow->removeAllEventListeners();
2334
ap@webkit.orga0a19872008-02-05 09:34:18 +00002335 if (m_frame)
2336 m_frame->loader()->didExplicitOpen();
darinb9481ed2006-03-20 02:57:59 +00002337}
2338
eric@webkit.org0cea84c2010-08-19 19:32:02 +00002339void Document::detachParser()
2340{
2341 if (!m_parser)
2342 return;
2343 m_parser->detach();
2344 m_parser.clear();
2345}
2346
darinb9481ed2006-03-20 02:57:59 +00002347void Document::cancelParsing()
2348{
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002349 if (!m_parser)
2350 return;
2351
2352 // We have to clear the parser to avoid possibly triggering
2353 // the onload handler when closing as a side effect of a cancel-style
2354 // change, such as opening a new document or closing the window while
2355 // still parsing
2356 detachParser();
2357 explicitClose();
darinb9481ed2006-03-20 02:57:59 +00002358}
2359
2360void Document::implicitOpen()
2361{
2362 cancelParsing();
2363
eric@webkit.org871c3a72009-10-13 20:27:04 +00002364 removeChildren();
2365
hyatt@apple.comce8ee2a2010-08-27 20:29:34 +00002366 setCompatibilityMode(NoQuirksMode);
2367
abarth@webkit.org5d72ad22010-06-14 04:40:20 +00002368 m_parser = createParser();
darinb9481ed2006-03-20 02:57:59 +00002369 setParsing(true);
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00002370 setReadyState(Loading);
darinb9481ed2006-03-20 02:57:59 +00002371}
2372
zecke@webkit.org6c03d342009-01-31 03:51:37 +00002373HTMLElement* Document::body() const
darinb9481ed2006-03-20 02:57:59 +00002374{
bdashf45c4e32007-01-24 03:44:47 +00002375 Node* de = documentElement();
darinb9481ed2006-03-20 02:57:59 +00002376 if (!de)
2377 return 0;
2378
2379 // try to prefer a FRAMESET element over BODY
2380 Node* body = 0;
2381 for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
2382 if (i->hasTagName(framesetTag))
yael.aharon@nokia.com3be82c12011-02-09 23:13:27 +00002383 return toHTMLElement(i);
darinb9481ed2006-03-20 02:57:59 +00002384
hyatt@apple.combf26cc02008-10-14 20:35:36 +00002385 if (i->hasTagName(bodyTag) && !body)
darinb9481ed2006-03-20 02:57:59 +00002386 body = i;
2387 }
yael.aharon@nokia.com3be82c12011-02-09 23:13:27 +00002388 return toHTMLElement(body);
bdashf45c4e32007-01-24 03:44:47 +00002389}
2390
andersca@apple.comd645ac62011-06-20 20:21:56 +00002391void Document::setBody(PassRefPtr<HTMLElement> prpNewBody, ExceptionCode& ec)
oliver9119a9c2007-10-12 15:13:16 +00002392{
andersca@apple.comd645ac62011-06-20 20:21:56 +00002393 RefPtr<HTMLElement> newBody = prpNewBody;
2394
inferno@chromium.orge2b8e392011-06-01 23:13:53 +00002395 if (!newBody || !documentElement() || !newBody->hasTagName(bodyTag)) {
oliver9119a9c2007-10-12 15:13:16 +00002396 ec = HIERARCHY_REQUEST_ERR;
2397 return;
2398 }
2399
inferno@chromium.orge2b8e392011-06-01 23:13:53 +00002400 if (newBody->document() && newBody->document() != this) {
inferno@chromium.org06e516e2011-06-02 02:49:37 +00002401 ec = 0;
inferno@chromium.orge2b8e392011-06-01 23:13:53 +00002402 RefPtr<Node> node = importNode(newBody.get(), true, ec);
2403 if (ec)
2404 return;
2405
2406 newBody = toHTMLElement(node.get());
2407 }
2408
oliver9119a9c2007-10-12 15:13:16 +00002409 HTMLElement* b = body();
2410 if (!b)
andersca@apple.comd645ac62011-06-20 20:21:56 +00002411 documentElement()->appendChild(newBody.release(), ec);
oliver9119a9c2007-10-12 15:13:16 +00002412 else
andersca@apple.comd645ac62011-06-20 20:21:56 +00002413 documentElement()->replaceChild(newBody.release(), b, ec);
oliver9119a9c2007-10-12 15:13:16 +00002414}
2415
darina6a0caf2007-01-25 00:16:44 +00002416HTMLHeadElement* Document::head()
bdashf45c4e32007-01-24 03:44:47 +00002417{
2418 Node* de = documentElement();
2419 if (!de)
2420 return 0;
2421
2422 for (Node* e = de->firstChild(); e; e = e->nextSibling())
2423 if (e->hasTagName(headTag))
darina6a0caf2007-01-25 00:16:44 +00002424 return static_cast<HTMLHeadElement*>(e);
bdashf45c4e32007-01-24 03:44:47 +00002425
2426 return 0;
darinb9481ed2006-03-20 02:57:59 +00002427}
2428
2429void Document::close()
2430{
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002431 // FIXME: We should follow the specification more closely:
2432 // http://www.whatwg.org/specs/web-apps/current-work/#dom-document-close
2433
tonyg@chromium.org517fd462011-05-05 22:38:09 +00002434 if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript() || !scriptableDocumentParser()->isParsing())
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002435 return;
2436
2437 explicitClose();
2438}
2439
2440void Document::explicitClose()
2441{
abarth@webkit.org14a3bdf2011-06-11 00:56:13 +00002442 if (m_parser)
2443 m_parser->finish();
2444
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002445 if (!m_frame) {
ggarend9f8cfd2007-07-10 16:25:40 +00002446 // Because we have no frame, we don't know if all loading has completed,
2447 // so we just call implicitClose() immediately. FIXME: This might fire
2448 // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
2449 implicitClose();
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002450 return;
ggarend9f8cfd2007-07-10 16:25:40 +00002451 }
abarth@webkit.org01e4cc02011-02-09 23:07:45 +00002452
abarth@webkit.org14a3bdf2011-06-11 00:56:13 +00002453 m_frame->loader()->checkCompleted();
darinb9481ed2006-03-20 02:57:59 +00002454}
2455
2456void Document::implicitClose()
2457{
2458 // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached.
2459 if (m_inStyleRecalc) {
2460 m_closeAfterStyleRecalc = true;
2461 return;
2462 }
2463
abarth@webkit.org88b4e6b2010-10-04 22:09:57 +00002464 bool wasLocationChangePending = frame() && frame()->navigationScheduler()->locationChangePending();
abarth@webkit.org5d72ad22010-06-14 04:40:20 +00002465 bool doload = !parsing() && m_parser && !m_processingLoadEvent && !wasLocationChangePending;
darinb9481ed2006-03-20 02:57:59 +00002466
2467 if (!doload)
2468 return;
2469
2470 m_processingLoadEvent = true;
2471
eric@webkit.orge37f5952010-06-28 07:56:10 +00002472 ScriptableDocumentParser* parser = scriptableDocumentParser();
2473 m_wellFormed = parser && parser->wellFormed();
ap2cb6b942006-11-20 19:56:38 +00002474
abarth@webkit.org5d72ad22010-06-14 04:40:20 +00002475 // We have to clear the parser, in case someone document.write()s from the
darinb9481ed2006-03-20 02:57:59 +00002476 // onLoad event handler, as in Radar 3206524.
eric@webkit.org0cea84c2010-08-19 19:32:02 +00002477 detachParser();
darinb9481ed2006-03-20 02:57:59 +00002478
antti@apple.com6c76e542008-03-13 21:20:31 +00002479 // Parser should have picked up all preloads by now
abarth@webkit.org17d66c62010-09-08 10:26:02 +00002480 m_cachedResourceLoader->clearPreloads();
antti@apple.com6c76e542008-03-13 21:20:31 +00002481
beidson@apple.com26265142008-04-23 00:13:31 +00002482 // FIXME: We kick off the icon loader when the Document is done parsing.
2483 // There are earlier opportunities we could start it:
2484 // -When the <head> finishes parsing
2485 // -When any new HTMLLinkElement is inserted into the document
2486 // But those add a dynamic component to the favicon that has UI
2487 // ramifications, and we need to decide what is the Right Thing To Do(tm)
2488 Frame* f = frame();
abarth@webkit.org4e009972011-06-13 20:36:03 +00002489 if (f) {
2490 f->loader()->icon()->startLoader();
cmarrin@apple.come6a27002010-11-05 21:45:37 +00002491 f->animation()->resumeAnimationsForDocument(this);
abarth@webkit.org4e009972011-06-13 20:36:03 +00002492 }
dino@apple.com6b8acf72008-08-08 20:44:14 +00002493
ap@apple.com66e61bd2009-12-14 21:47:04 +00002494 ImageLoader::dispatchPendingBeforeLoadEvents();
2495 ImageLoader::dispatchPendingLoadEvents();
abarth@webkit.org71def432012-03-27 01:59:06 +00002496 ImageLoader::dispatchPendingErrorEvents();
zimmermann@webkit.org3d2114c2012-02-08 10:21:49 +00002497
dbates@webkit.org03278c12012-02-24 16:50:55 +00002498 HTMLLinkElement::dispatchPendingLoadEvents();
2499 HTMLStyleElement::dispatchPendingLoadEvents();
2500
zimmermann@webkit.org3d2114c2012-02-08 10:21:49 +00002501#if ENABLE(SVG)
2502 // To align the HTML load event and the SVGLoad event for the outermost <svg> element, fire it from
2503 // here, instead of doing it from SVGElement::finishedParsingChildren (if externalResourcesRequired="false",
2504 // which is the default, for ='true' its fired at a later time, once all external resources finished loading).
2505 if (svgExtensions())
2506 accessSVGExtensions()->dispatchSVGLoadEventToOutermostSVGElements();
2507#endif
2508
ggaren@apple.com521f64b2009-09-24 05:53:23 +00002509 dispatchWindowLoadEvent();
beidson@apple.com43a414c2010-03-19 18:25:21 +00002510 enqueuePageshowEvent(PageshowEventNotPersisted);
commit-queue@webkit.org72354062010-09-02 01:00:51 +00002511 enqueuePopstateEvent(m_pendingStateObject ? m_pendingStateObject.release() : SerializedScriptValue::nullValue());
beidson@apple.com08c61752009-12-03 19:04:40 +00002512
beidson@apple.com26265142008-04-23 00:13:31 +00002513 if (f)
darinc370e7e2006-11-08 05:52:27 +00002514 f->loader()->handledOnloadEvents();
darinb9481ed2006-03-20 02:57:59 +00002515#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2516 if (!ownerElement())
2517 printf("onload fired at %d\n", elapsedTime());
2518#endif
2519
weinigc34c71c2007-03-09 16:05:37 +00002520 // An event handler may have removed the frame
commit-queue@webkit.org2b7d6922012-04-05 04:22:50 +00002521 if (!frame()) {
2522 m_processingLoadEvent = false;
weinigc34c71c2007-03-09 16:05:37 +00002523 return;
commit-queue@webkit.org2b7d6922012-04-05 04:22:50 +00002524 }
weinigc34c71c2007-03-09 16:05:37 +00002525
darinb9481ed2006-03-20 02:57:59 +00002526 // Make sure both the initial layout and reflow happen after the onload
2527 // fires. This will improve onload scores, and other browsers do it.
2528 // If they wanna cheat, we can too. -dwh
2529
abarth@webkit.org88b4e6b2010-10-04 22:09:57 +00002530 if (frame()->navigationScheduler()->locationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
darinb9481ed2006-03-20 02:57:59 +00002531 // Just bail out. Before or during the onload we were shifted to another page.
2532 // The old i-Bench suite does this. When this happens don't bother painting or laying out.
commit-queue@webkit.org2b7d6922012-04-05 04:22:50 +00002533 m_processingLoadEvent = false;
darinb9481ed2006-03-20 02:57:59 +00002534 view()->unscheduleRelayout();
2535 return;
2536 }
2537
ggarena57755c2007-07-09 21:08:10 +00002538 frame()->loader()->checkCallImplicitClose();
cfleizach@apple.com21657b62009-07-07 19:05:45 +00002539 RenderObject* renderObject = renderer();
2540
hyatt@apple.com82b02812009-04-08 22:33:48 +00002541 // We used to force a synchronous display and flush here. This really isn't
2542 // necessary and can in fact be actively harmful if pages are loading at a rate of > 60fps
2543 // (if your platform is syncing flushes and limiting them to 60fps).
2544 m_overMinimumLayoutThreshold = true;
darinb9481ed2006-03-20 02:57:59 +00002545 if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00002546 updateStyleIfNeeded();
darinb9481ed2006-03-20 02:57:59 +00002547
2548 // Always do a layout after loading if needed.
cfleizach@apple.com21657b62009-07-07 19:05:45 +00002549 if (view() && renderObject && (!renderObject->firstChild() || renderObject->needsLayout()))
darinb9481ed2006-03-20 02:57:59 +00002550 view()->layout();
2551 }
hyatt72907f42006-10-17 08:52:26 +00002552
commit-queue@webkit.org2b7d6922012-04-05 04:22:50 +00002553 m_processingLoadEvent = false;
2554
commit-queue@webkit.org666227b2010-09-24 07:51:48 +00002555#if PLATFORM(MAC) || PLATFORM(CHROMIUM)
pkasting@chromium.org0921df42011-11-18 01:28:56 +00002556 if (f && renderObject && AXObjectCache::accessibilityEnabled()) {
cfleizach@apple.com21657b62009-07-07 19:05:45 +00002557 // The AX cache may have been cleared at this point, but we need to make sure it contains an
2558 // AX object to send the notification to. getOrCreate will make sure that an valid AX object
2559 // exists in the cache (we ignore the return value because we don't need it here). This is
2560 // only safe to call when a layout is not in progress, so it can not be used in postNotification.
2561 axObjectCache()->getOrCreate(renderObject);
pkasting@chromium.org0921df42011-11-18 01:28:56 +00002562 if (this == topDocument())
2563 axObjectCache()->postNotification(renderObject, AXObjectCache::AXLoadComplete, true);
2564 else {
2565 // AXLoadComplete can only be posted on the top document, so if it's a document
dmazzoni@google.com709c0b02011-12-15 04:40:50 +00002566 // in an iframe that just finished loading, post AXLayoutComplete instead.
2567 axObjectCache()->postNotification(renderObject, AXObjectCache::AXLayoutComplete, true);
pkasting@chromium.org0921df42011-11-18 01:28:56 +00002568 }
cfleizach@apple.com4c5c29c2009-07-24 00:35:28 +00002569 }
darinb9481ed2006-03-20 02:57:59 +00002570#endif
2571
mjsd2948ef2007-02-26 19:29:04 +00002572#if ENABLE(SVG)
darinb9481ed2006-03-20 02:57:59 +00002573 if (svgExtensions())
eseidel4e524622006-05-31 17:25:30 +00002574 accessSVGExtensions()->startAnimations();
darinb9481ed2006-03-20 02:57:59 +00002575#endif
2576}
2577
2578void Document::setParsing(bool b)
2579{
2580 m_bParsing = b;
2581 if (!m_bParsing && view())
2582 view()->scheduleRelayout();
2583
2584#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2585 if (!ownerElement() && !m_bParsing)
2586 printf("Parsing finished at %d\n", elapsedTime());
2587#endif
2588}
2589
2590bool Document::shouldScheduleLayout()
2591{
darin@apple.com8bf1fe02008-11-10 17:06:04 +00002592 // This function will only be called when FrameView thinks a layout is needed.
2593 // This enforces a couple extra rules.
2594 //
2595 // (a) Only schedule a layout once the stylesheets are loaded.
2596 // (b) Only schedule layout once we have a body element.
2597
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00002598 return (haveStylesheetsLoaded() && body())
2599 || (documentElement() && !documentElement()->hasTagName(htmlTag));
darinb9481ed2006-03-20 02:57:59 +00002600}
tonyg@chromium.org991ea592011-02-26 11:20:11 +00002601
2602bool Document::isLayoutTimerActive()
2603{
steveblock@google.come1919eb2011-09-01 12:37:04 +00002604 return view() && view()->layoutPending() && !minimumLayoutDelay();
tonyg@chromium.org991ea592011-02-26 11:20:11 +00002605}
darinb9481ed2006-03-20 02:57:59 +00002606
2607int Document::minimumLayoutDelay()
2608{
2609 if (m_overMinimumLayoutThreshold)
steveblock@google.come1919eb2011-09-01 12:37:04 +00002610 return 0;
darinb9481ed2006-03-20 02:57:59 +00002611
2612 int elapsed = elapsedTime();
2613 m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
2614
2615 // We'll want to schedule the timer to fire at the minimum layout threshold.
steveblock@google.come1919eb2011-09-01 12:37:04 +00002616 return max(0, cLayoutScheduleThreshold - elapsed);
darinb9481ed2006-03-20 02:57:59 +00002617}
2618
2619int Document::elapsedTime() const
2620{
2621 return static_cast<int>((currentTime() - m_startTime) * 1000);
2622}
2623
treat@webkit.org21553292009-02-13 21:01:31 +00002624void Document::write(const SegmentedString& text, Document* ownerDocument)
darinb9481ed2006-03-20 02:57:59 +00002625{
commit-queue@webkit.orgb7b2b522011-02-02 00:22:52 +00002626 NestingLevelIncrementer nestingLevelIncrementer(m_writeRecursionDepth);
2627
2628 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > 1) && m_writeRecursionIsTooDeep;
2629 m_writeRecursionIsTooDeep = (m_writeRecursionDepth > cMaxWriteRecursionDepth) || m_writeRecursionIsTooDeep;
2630
2631 if (m_writeRecursionIsTooDeep)
2632 return;
2633
darinb9481ed2006-03-20 02:57:59 +00002634#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2635 if (!ownerElement())
2636 printf("Beginning a document.write at %d\n", elapsedTime());
2637#endif
darin@apple.comeeec1272009-02-13 16:20:16 +00002638
abarth@webkit.org8a828c12010-07-23 22:14:02 +00002639 bool hasInsertionPoint = m_parser && m_parser->hasInsertionPoint();
tonyg@chromium.org8500eb82010-10-22 01:27:27 +00002640 if (!hasInsertionPoint && m_ignoreDestructiveWriteCount)
abarth@webkit.org8a828c12010-07-23 22:14:02 +00002641 return;
2642
2643 if (!hasInsertionPoint)
treat@webkit.org21553292009-02-13 21:01:31 +00002644 open(ownerDocument);
treat@webkit.org21553292009-02-13 21:01:31 +00002645
abarth@webkit.org5d72ad22010-06-14 04:40:20 +00002646 ASSERT(m_parser);
eric@webkit.org5cfd5562010-06-25 21:37:08 +00002647 m_parser->insert(text);
ap@apple.com97b0fe72010-05-14 20:32:08 +00002648
darinb9481ed2006-03-20 02:57:59 +00002649#ifdef INSTRUMENT_LAYOUT_SCHEDULING
2650 if (!ownerElement())
2651 printf("Ending a document.write at %d\n", elapsedTime());
ap@webkit.orga0a19872008-02-05 09:34:18 +00002652#endif
darinb9481ed2006-03-20 02:57:59 +00002653}
2654
treat@webkit.org21553292009-02-13 21:01:31 +00002655void Document::write(const String& text, Document* ownerDocument)
2656{
2657 write(SegmentedString(text), ownerDocument);
2658}
2659
abarth@webkit.orgbf2c13a2008-06-12 06:41:53 +00002660void Document::writeln(const String& text, Document* ownerDocument)
darinb9481ed2006-03-20 02:57:59 +00002661{
abarth@webkit.orgbf2c13a2008-06-12 06:41:53 +00002662 write(text, ownerDocument);
2663 write("\n", ownerDocument);
darinb9481ed2006-03-20 02:57:59 +00002664}
2665
ap@webkit.orgbe35d512008-10-31 09:44:03 +00002666const KURL& Document::virtualURL() const
2667{
2668 return m_url;
2669}
2670
jchaffraix@webkit.org715c47a2008-12-23 19:01:12 +00002671KURL Document::virtualCompleteURL(const String& url) const
2672{
2673 return completeURL(url);
2674}
2675
kbr@google.com7bf42ee2011-02-15 22:53:44 +00002676double Document::minimumTimerInterval() const
2677{
2678 Page* p = page();
2679 if (!p)
2680 return ScriptExecutionContext::minimumTimerInterval();
2681 return p->settings()->minDOMTimerInterval();
2682}
2683
yurys@chromium.orgc8a06eb2011-01-20 09:28:54 +00002684EventTarget* Document::errorEventTarget()
2685{
2686 return domWindow();
2687}
2688
vsevik@chromium.org0c3bdd92012-01-12 10:56:52 +00002689void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, PassRefPtr<ScriptCallStack> callStack)
yurys@chromium.orgc8a06eb2011-01-20 09:28:54 +00002690{
vsevik@chromium.org0c3bdd92012-01-12 10:56:52 +00002691 addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack);
yurys@chromium.orgc8a06eb2011-01-20 09:28:54 +00002692}
2693
darin@apple.com640fa302008-02-15 05:03:55 +00002694void Document::setURL(const KURL& url)
darinb9481ed2006-03-20 02:57:59 +00002695{
abarth@webkit.org86d04452008-06-16 04:42:51 +00002696 const KURL& newURL = url.isEmpty() ? blankURL() : url;
2697 if (newURL == m_url)
kmcculloadfd67d2007-03-03 02:18:43 +00002698 return;
2699
abarth@webkit.org86d04452008-06-16 04:42:51 +00002700 m_url = newURL;
abarth@webkit.org761e1002008-06-16 04:43:06 +00002701 m_documentURI = m_url.string();
abarth@webkit.org86d04452008-06-16 04:42:51 +00002702 updateBaseURL();
morrita@google.com71ae0392012-07-09 08:53:48 +00002703 contextFeatures()->urlDidChange(this);
abarth@webkit.org86d04452008-06-16 04:42:51 +00002704}
darinb9481ed2006-03-20 02:57:59 +00002705
abarth@webkit.org86d04452008-06-16 04:42:51 +00002706void Document::updateBaseURL()
2707{
antti@apple.comf89be042011-12-12 18:56:20 +00002708 KURL oldBaseURL = m_baseURL;
ap@webkit.org3db1ca12009-01-26 06:42:30 +00002709 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2 HTML], the base URI is computed using
2710 // first the value of the href attribute of the HTML BASE element if any, and the value of the documentURI attribute
2711 // from the Document interface otherwise.
jcivelli@chromium.org5de71312011-11-17 03:08:21 +00002712 if (!m_baseElementURL.isEmpty())
2713 m_baseURL = m_baseElementURL;
2714 else if (!m_baseURLOverride.isEmpty())
2715 m_baseURL = m_baseURLOverride;
2716 else {
commit-queue@webkit.org4ef90532012-06-12 18:02:56 +00002717 // The documentURI attribute is read-only from JavaScript, but writable from Objective C, so we need to retain
2718 // this fallback behavior. We use a null base URL, since the documentURI attribute is an arbitrary string
2719 // and DOM 3 Core does not specify how it should be resolved.
ap@webkit.org3db1ca12009-01-26 06:42:30 +00002720 m_baseURL = KURL(KURL(), documentURI());
jcivelli@chromium.org5de71312011-11-17 03:08:21 +00002721 }
haraken@chromium.org3981f522012-06-02 19:23:25 +00002722 selectorQueryCache()->invalidate();
jcivelli@chromium.org5de71312011-11-17 03:08:21 +00002723
abarth@webkit.org761e1002008-06-16 04:43:06 +00002724 if (!m_baseURL.isValid())
2725 m_baseURL = KURL();
abarth@webkit.org86d04452008-06-16 04:42:51 +00002726
antti@apple.comfe126eb2012-04-25 22:42:47 +00002727 if (m_elemSheet) {
2728 // Element sheet is silly. It never contains anything.
antti@apple.com384e66f2012-05-23 17:17:43 +00002729 ASSERT(!m_elemSheet->contents()->ruleCount());
2730 bool usesRemUnits = m_elemSheet->contents()->usesRemUnits();
antti@apple.comfe126eb2012-04-25 22:42:47 +00002731 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
2732 // FIXME: So we are not really the parser. The right fix is to eliminate the element sheet completely.
antti@apple.com384e66f2012-05-23 17:17:43 +00002733 m_elemSheet->contents()->parserSetUsesRemUnits(usesRemUnits);
antti@apple.comfe126eb2012-04-25 22:42:47 +00002734 }
2735
antti@apple.comf89be042011-12-12 18:56:20 +00002736 if (!equalIgnoringFragmentIdentifier(oldBaseURL, m_baseURL)) {
2737 // Base URL change changes any relative visited links.
2738 // FIXME: There are other URLs in the tree that would need to be re-evaluated on dynamic base URL change. Style should be invalidated too.
2739 for (Node* node = firstChild(); node; node = node->traverseNextNode()) {
2740 if (node->hasTagName(aTag))
2741 static_cast<HTMLAnchorElement*>(node)->invalidateCachedVisitedLinkHash();
2742 }
2743 }
weinigd1f53f02007-02-20 01:22:06 +00002744}
2745
jcivelli@chromium.org5de71312011-11-17 03:08:21 +00002746void Document::setBaseURLOverride(const KURL& url)
2747{
2748 m_baseURLOverride = url;
2749 updateBaseURL();
2750}
2751
darin@apple.com17c2d2c2010-08-29 05:48:44 +00002752void Document::processBaseElement()
2753{
2754 // Find the first href attribute in a base element and the first target attribute in a base element.
2755 const AtomicString* href = 0;
2756 const AtomicString* target = 0;
2757 for (Node* node = document()->firstChild(); node && (!href || !target); node = node->traverseNextNode()) {
2758 if (node->hasTagName(baseTag)) {
2759 if (!href) {
2760 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(hrefAttr);
2761 if (!value.isNull())
2762 href = &value;
2763 }
2764 if (!target) {
2765 const AtomicString& value = static_cast<Element*>(node)->fastGetAttribute(targetAttr);
2766 if (!value.isNull())
2767 target = &value;
2768 }
2769 }
2770 }
2771
2772 // FIXME: Since this doesn't share code with completeURL it may not handle encodings correctly.
2773 KURL baseElementURL;
2774 if (href) {
darin@apple.com7b7981b2010-10-01 00:04:02 +00002775 String strippedHref = stripLeadingAndTrailingHTMLSpaces(*href);
abarth@webkit.orgfb50fc92011-02-05 22:55:14 +00002776 if (!strippedHref.isEmpty())
darin@apple.com17c2d2c2010-08-29 05:48:44 +00002777 baseElementURL = KURL(url(), strippedHref);
2778 }
2779 if (m_baseElementURL != baseElementURL) {
2780 m_baseElementURL = baseElementURL;
2781 updateBaseURL();
2782 }
2783
2784 m_baseTarget = target ? *target : nullAtom;
2785}
2786
dimich@chromium.org5f1b3fe2009-02-20 07:23:00 +00002787String Document::userAgent(const KURL& url) const
2788{
2789 return frame() ? frame()->loader()->userAgent(url) : String();
2790}
2791
commit-queue@webkit.org7415e102012-09-14 23:33:20 +00002792void Document::disableEval(const String& errorMessage)
weinig@apple.com76f3d932011-10-05 00:52:50 +00002793{
2794 if (!frame())
2795 return;
2796
commit-queue@webkit.org7415e102012-09-14 23:33:20 +00002797 frame()->script()->disableEval(errorMessage);
weinig@apple.com76f3d932011-10-05 00:52:50 +00002798}
2799
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002800bool Document::canNavigate(Frame* targetFrame)
2801{
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002802 if (!m_frame)
2803 return false;
2804
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002805 // FIXME: We shouldn't call this function without a target frame, but
2806 // fast/forms/submit-to-blank-multiple-times.html depends on this function
2807 // returning true when supplied with a 0 targetFrame.
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002808 if (!targetFrame)
2809 return true;
2810
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002811 // Frame-busting is generally allowed (unless we're sandboxed and prevent from frame-busting).
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002812 if (!isSandboxed(SandboxTopNavigation) && targetFrame == m_frame->tree()->top())
2813 return true;
2814
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002815 if (isSandboxed(SandboxNavigation)) {
2816 if (targetFrame->tree()->isDescendantOf(m_frame))
2817 return true;
2818
2819 printNavigationErrorMessage(targetFrame, url());
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002820 return false;
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002821 }
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002822
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002823 // This is the normal case. A document can navigate its decendant frames,
2824 // or, more generally, a document can navigate a frame if the document is
2825 // in the same origin as any of that frame's ancestors (in the frame
2826 // hierarchy).
2827 //
2828 // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for
2829 // historical information about this security check.
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002830 if (canAccessAncestor(securityOrigin(), targetFrame))
2831 return true;
2832
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002833 // Top-level frames are easier to navigate than other frames because they
2834 // display their URLs in the address bar (in most browsers). However, there
2835 // are still some restrictions on navigation to avoid nuisance attacks.
2836 // Specifically, a document can navigate a top-level frame if that frame
2837 // opened the document or if the document is the same-origin with any of
2838 // the top-level frame's opener's ancestors (in the frame hierarchy).
2839 //
2840 // In both of these cases, the document performing the navigation is in
2841 // some way related to the frame being navigate (e.g., by the "opener"
2842 // and/or "parent" relation). Requiring some sort of relation prevents a
2843 // document from navigating arbitrary, unrelated top-level frames.
2844 if (!targetFrame->tree()->parent()) {
2845 if (targetFrame == m_frame->loader()->opener())
2846 return true;
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002847
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002848 if (canAccessAncestor(securityOrigin(), targetFrame->loader()->opener()))
2849 return true;
2850 }
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002851
abarth@webkit.org0f97abe2012-04-02 02:43:17 +00002852 printNavigationErrorMessage(targetFrame, url());
abarth@webkit.orga9da3b02012-03-27 01:09:43 +00002853 return false;
2854}
2855
tsepez@chromium.org8d3c2c12012-04-17 19:03:42 +00002856Frame* Document::findUnsafeParentScrollPropagationBoundary()
tsepez@chromium.orgf8960562012-04-06 22:15:02 +00002857{
tsepez@chromium.org8d3c2c12012-04-17 19:03:42 +00002858 Frame* currentFrame = m_frame;
2859 Frame* ancestorFrame = currentFrame->tree()->parent();
2860
2861 while (ancestorFrame) {
tsepez@chromium.orgf8960562012-04-06 22:15:02 +00002862 if (!ancestorFrame->document()->securityOrigin()->canAccess(securityOrigin()))
tsepez@chromium.org8d3c2c12012-04-17 19:03:42 +00002863 return currentFrame;
2864 currentFrame = ancestorFrame;
2865 ancestorFrame = ancestorFrame->tree()->parent();
tsepez@chromium.orgf8960562012-04-06 22:15:02 +00002866 }
tsepez@chromium.org8d3c2c12012-04-17 19:03:42 +00002867 return 0;
tsepez@chromium.orgf8960562012-04-06 22:15:02 +00002868}
2869
mihaip@chromium.org56051162011-07-27 18:34:07 +00002870
eric@webkit.org876b40e2012-05-09 00:52:08 +00002871void Document::seamlessParentUpdatedStylesheets()
2872{
2873 styleResolverChanged(RecalcStyleImmediately);
2874}
2875
antti@apple.come5a88a72012-09-24 22:14:47 +00002876void Document::didRemoveAllPendingStylesheet()
2877{
2878 m_needsNotifyRemoveAllPendingStylesheet = false;
2879
2880 styleResolverChanged(RecalcStyleIfNeeded);
2881
2882 if (ScriptableDocumentParser* parser = scriptableDocumentParser())
2883 parser->executeScriptsWaitingForStylesheets();
2884
2885 if (m_gotoAnchorNeededAfterStylesheetsLoad && view())
2886 view()->scrollToFragment(m_url);
2887}
2888
darinb9481ed2006-03-20 02:57:59 +00002889CSSStyleSheet* Document::elementSheet()
2890{
2891 if (!m_elemSheet)
antti@apple.comfe126eb2012-04-25 22:42:47 +00002892 m_elemSheet = CSSStyleSheet::createInline(this, m_baseURL);
darinb9481ed2006-03-20 02:57:59 +00002893 return m_elemSheet.get();
2894}
2895
darinb9481ed2006-03-20 02:57:59 +00002896int Document::nodeAbsIndex(Node *node)
2897{
ggarenf9f32ae2007-03-26 20:08:53 +00002898 ASSERT(node->document() == this);
darinb9481ed2006-03-20 02:57:59 +00002899
2900 int absIndex = 0;
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00002901 for (Node* n = node; n && n != this; n = n->traversePreviousNode())
darinb9481ed2006-03-20 02:57:59 +00002902 absIndex++;
2903 return absIndex;
2904}
2905
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00002906Node* Document::nodeWithAbsIndex(int absIndex)
darinb9481ed2006-03-20 02:57:59 +00002907{
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00002908 Node* n = this;
2909 for (int i = 0; n && (i < absIndex); i++)
darinb9481ed2006-03-20 02:57:59 +00002910 n = n->traverseNextNode();
darinb9481ed2006-03-20 02:57:59 +00002911 return n;
2912}
2913
weinig@apple.com5af461c2009-04-08 22:16:23 +00002914void Document::processHttpEquiv(const String& equiv, const String& content)
darinb9481ed2006-03-20 02:57:59 +00002915{
ggarenf9f32ae2007-03-26 20:08:53 +00002916 ASSERT(!equiv.isNull() && !content.isNull());
darinb9481ed2006-03-20 02:57:59 +00002917
weinig@apple.com5af461c2009-04-08 22:16:23 +00002918 Frame* frame = this->frame();
darinb9481ed2006-03-20 02:57:59 +00002919
2920 if (equalIgnoringCase(equiv, "default-style")) {
2921 // The preferred style set has been overridden as per section
2922 // 14.3.2 of the HTML4.0 specification. We need to update the
2923 // sheet used variable and then update our style selector.
2924 // For more info, see the test at:
2925 // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
2926 // -dwh
antti@apple.come5a88a72012-09-24 22:14:47 +00002927 m_styleSheetCollection->setSelectedStylesheetSetName(content);
2928 m_styleSheetCollection->setPreferredStylesheetSetName(content);
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00002929 styleResolverChanged(DeferRecalcStyle);
eseidelcff0a722006-03-22 22:27:45 +00002930 } else if (equalIgnoringCase(equiv, "refresh")) {
ape9991d52006-12-08 18:19:51 +00002931 double delay;
2932 String url;
ape74d7f92007-02-18 12:48:44 +00002933 if (frame && parseHTTPRefresh(content, true, delay, url)) {
ape9991d52006-12-08 18:19:51 +00002934 if (url.isEmpty())
japhet@chromium.org5a152742011-01-28 01:22:16 +00002935 url = m_url.string();
ape9991d52006-12-08 18:19:51 +00002936 else
darin@apple.com640fa302008-02-15 05:03:55 +00002937 url = completeURL(url).string();
abarth@webkit.org88b4e6b2010-10-04 22:09:57 +00002938 frame->navigationScheduler()->scheduleRedirect(delay, url);
darinb9481ed2006-03-20 02:57:59 +00002939 }
eseidelcff0a722006-03-22 22:27:45 +00002940 } else if (equalIgnoringCase(equiv, "set-cookie")) {
darinc370e7e2006-11-08 05:52:27 +00002941 // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00002942 if (isHTMLDocument()) {
2943 ExceptionCode ec; // Exception (for sandboxed documents) ignored.
2944 static_cast<HTMLDocument*>(this)->setCookie(content, ec);
2945 }
eric@webkit.org1658b662008-01-09 09:23:16 +00002946 } else if (equalIgnoringCase(equiv, "content-language"))
2947 setContentLanguage(content);
collinj@webkit.org9c672f62008-09-19 04:15:14 +00002948 else if (equalIgnoringCase(equiv, "x-dns-prefetch-control"))
2949 parseDNSPrefetchControlHeader(content);
weinig@apple.com5af461c2009-04-08 22:16:23 +00002950 else if (equalIgnoringCase(equiv, "x-frame-options")) {
tonyg@chromium.org254d90f2010-09-16 16:12:23 +00002951 if (frame) {
2952 FrameLoader* frameLoader = frame->loader();
2953 if (frameLoader->shouldInterruptLoadForXFrameOptions(content, url())) {
2954 frameLoader->stopAllLoaders();
darin@apple.com1cf3d562010-12-07 16:23:03 +00002955 frame->navigationScheduler()->scheduleLocationChange(securityOrigin(), blankURL(), String());
eric@webkit.orgc3ee4d02010-05-15 09:10:44 +00002956
abarth@webkit.orgf6d1b8c2012-08-29 07:38:10 +00002957 DEFINE_STATIC_LOCAL(String, consoleMessage, (ASCIILiteral("Refused to display document because display forbidden by X-Frame-Options.\n")));
abarth@webkit.org0ed32772011-11-08 00:57:10 +00002958 addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage);
tonyg@chromium.org254d90f2010-09-16 16:12:23 +00002959 }
weinig@apple.com5af461c2009-04-08 22:16:23 +00002960 }
abarth@webkit.org3285b43b2011-04-07 10:04:22 +00002961 } else if (equalIgnoringCase(equiv, "x-webkit-csp"))
abarth@webkit.orgbd0c7752011-05-07 02:13:06 +00002962 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::EnforcePolicy);
2963 else if (equalIgnoringCase(equiv, "x-webkit-csp-report-only"))
2964 contentSecurityPolicy()->didReceiveHeader(content, ContentSecurityPolicy::ReportOnly);
darinb9481ed2006-03-20 02:57:59 +00002965}
2966
dbates@webkit.orgf6460f92010-04-17 04:40:14 +00002967// Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
2968static bool isSeparator(UChar c)
2969{
2970 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '=' || c == ',' || c == '\0';
2971}
2972
2973void Document::processArguments(const String& features, void* data, ArgumentsCallback callback)
2974{
2975 // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
2976 int keyBegin, keyEnd;
2977 int valueBegin, valueEnd;
2978
2979 int i = 0;
2980 int length = features.length();
2981 String buffer = features.lower();
2982 while (i < length) {
2983 // skip to first non-separator, but don't skip past the end of the string
2984 while (isSeparator(buffer[i])) {
2985 if (i >= length)
2986 break;
2987 i++;
2988 }
2989 keyBegin = i;
2990
2991 // skip to first separator
2992 while (!isSeparator(buffer[i]))
2993 i++;
2994 keyEnd = i;
2995
2996 // skip to first '=', but don't skip past a ',' or the end of the string
2997 while (buffer[i] != '=') {
2998 if (buffer[i] == ',' || i >= length)
2999 break;
3000 i++;
3001 }
3002
3003 // skip to first non-separator, but don't skip past a ',' or the end of the string
3004 while (isSeparator(buffer[i])) {
3005 if (buffer[i] == ',' || i >= length)
3006 break;
3007 i++;
3008 }
3009 valueBegin = i;
3010
3011 // skip to first separator
3012 while (!isSeparator(buffer[i]))
3013 i++;
3014 valueEnd = i;
3015
3016 ASSERT(i <= length);
3017
3018 String keyString = buffer.substring(keyBegin, keyEnd - keyBegin);
3019 String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
3020 callback(keyString, valueString, this, data);
3021 }
3022}
3023
commit-queue@webkit.org36e5ae12012-06-01 18:24:02 +00003024void Document::processViewport(const String& features, ViewportArguments::Type origin)
dbates@webkit.orgf6460f92010-04-17 04:40:14 +00003025{
3026 ASSERT(!features.isNull());
3027
commit-queue@webkit.org36e5ae12012-06-01 18:24:02 +00003028 if (origin < m_viewportArguments.type)
3029 return;
3030
3031 m_viewportArguments = ViewportArguments(origin);
luiz@webkit.orge0514c52010-09-24 21:54:25 +00003032 processArguments(features, (void*)&m_viewportArguments, &setViewportFeature);
3033
wangxianzhu@chromium.org8a6966f2012-02-07 04:16:50 +00003034 updateViewportArguments();
3035}
dbates@webkit.orgf6460f92010-04-17 04:40:14 +00003036
wangxianzhu@chromium.org8a6966f2012-02-07 04:16:50 +00003037void Document::updateViewportArguments()
3038{
commit-queue@webkit.org7adcbd82012-05-02 13:00:47 +00003039 if (page() && page()->mainFrame() == frame()) {
3040#ifndef NDEBUG
3041 m_didDispatchViewportPropertiesChanged = true;
3042#endif
wangxianzhu@chromium.org8a6966f2012-02-07 04:16:50 +00003043 page()->chrome()->dispatchViewportPropertiesDidChange(m_viewportArguments);
commit-queue@webkit.org7adcbd82012-05-02 13:00:47 +00003044 }
dbates@webkit.orgf6460f92010-04-17 04:40:14 +00003045}
3046
jochen@chromium.org4761ef52011-11-21 10:29:55 +00003047void Document::processReferrerPolicy(const String& policy)
3048{
3049 ASSERT(!policy.isNull());
3050
gavinp@chromium.org4b820562012-04-23 12:53:24 +00003051 m_referrerPolicy = ReferrerPolicyDefault;
jochen@chromium.org4761ef52011-11-21 10:29:55 +00003052
3053 if (equalIgnoringCase(policy, "never"))
gavinp@chromium.org4b820562012-04-23 12:53:24 +00003054 m_referrerPolicy = ReferrerPolicyNever;
jochen@chromium.org4761ef52011-11-21 10:29:55 +00003055 else if (equalIgnoringCase(policy, "always"))
gavinp@chromium.org4b820562012-04-23 12:53:24 +00003056 m_referrerPolicy = ReferrerPolicyAlways;
jochen@chromium.org4761ef52011-11-21 10:29:55 +00003057 else if (equalIgnoringCase(policy, "origin"))
gavinp@chromium.org4b820562012-04-23 12:53:24 +00003058 m_referrerPolicy = ReferrerPolicyOrigin;
jochen@chromium.org4761ef52011-11-21 10:29:55 +00003059}
3060
leviw@chromium.org3af17062011-08-18 00:36:48 +00003061MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const LayoutPoint& documentPoint, const PlatformMouseEvent& event)
darinb9481ed2006-03-20 02:57:59 +00003062{
ggarena523f082006-12-19 08:04:48 +00003063 ASSERT(!renderer() || renderer()->isRenderView());
3064
darinb9481ed2006-03-20 02:57:59 +00003065 if (!renderer())
leviw@chromium.org3af17062011-08-18 00:36:48 +00003066 return MouseEventWithHitTestResults(event, HitTestResult(LayoutPoint()));
darinb9481ed2006-03-20 02:57:59 +00003067
ggarena523f082006-12-19 08:04:48 +00003068 HitTestResult result(documentPoint);
jchaffraix@webkit.org9dbf6d12012-04-12 16:02:25 +00003069 renderView()->hitTest(request, result);
darinb9481ed2006-03-20 02:57:59 +00003070
treat@webkit.org16eda3f2009-02-02 20:46:48 +00003071 if (!request.readOnly())
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00003072 updateStyleIfNeeded();
darinb9481ed2006-03-20 02:57:59 +00003073
aroben3e7723d2007-07-05 02:59:41 +00003074 return MouseEventWithHitTestResults(event, result);
darinb9481ed2006-03-20 02:57:59 +00003075}
3076
3077// DOM Section 1.1.1
rolandsteiner@chromium.org6642a952011-04-14 05:44:29 +00003078bool Document::childTypeAllowed(NodeType type) const
darinb9481ed2006-03-20 02:57:59 +00003079{
3080 switch (type) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003081 case ATTRIBUTE_NODE:
3082 case CDATA_SECTION_NODE:
3083 case DOCUMENT_FRAGMENT_NODE:
3084 case DOCUMENT_NODE:
3085 case ENTITY_NODE:
3086 case ENTITY_REFERENCE_NODE:
3087 case NOTATION_NODE:
3088 case TEXT_NODE:
3089 case XPATH_NAMESPACE_NODE:
3090 return false;
3091 case COMMENT_NODE:
3092 case PROCESSING_INSTRUCTION_NODE:
3093 return true;
3094 case DOCUMENT_TYPE_NODE:
3095 case ELEMENT_NODE:
3096 // Documents may contain no more than one of each of these.
3097 // (One Element and one DocumentType.)
3098 for (Node* c = firstChild(); c; c = c->nextSibling())
3099 if (c->nodeType() == type)
3100 return false;
3101 return true;
darinb9481ed2006-03-20 02:57:59 +00003102 }
darin2b8671c2006-05-17 06:33:59 +00003103 return false;
darinb9481ed2006-03-20 02:57:59 +00003104}
3105
andersca229761c2007-02-12 23:24:15 +00003106bool Document::canReplaceChild(Node* newChild, Node* oldChild)
3107{
mitz@apple.com4e34eca2007-12-03 18:09:34 +00003108 if (!oldChild)
3109 // ContainerNode::replaceChild will raise a NOT_FOUND_ERR.
3110 return true;
3111
andersca229761c2007-02-12 23:24:15 +00003112 if (oldChild->nodeType() == newChild->nodeType())
3113 return true;
3114
3115 int numDoctypes = 0;
3116 int numElements = 0;
3117
3118 // First, check how many doctypes and elements we have, not counting
3119 // the child we're about to remove.
3120 for (Node* c = firstChild(); c; c = c->nextSibling()) {
3121 if (c == oldChild)
3122 continue;
3123
3124 switch (c->nodeType()) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003125 case DOCUMENT_TYPE_NODE:
3126 numDoctypes++;
3127 break;
3128 case ELEMENT_NODE:
3129 numElements++;
3130 break;
3131 default:
3132 break;
andersca229761c2007-02-12 23:24:15 +00003133 }
3134 }
3135
3136 // Then, see how many doctypes and elements might be added by the new child.
3137 if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
commit-queue@webkit.org0249dc82012-06-12 04:10:42 +00003138 for (Node* c = newChild->firstChild(); c; c = c->nextSibling()) {
andersca229761c2007-02-12 23:24:15 +00003139 switch (c->nodeType()) {
andersca229761c2007-02-12 23:24:15 +00003140 case ATTRIBUTE_NODE:
3141 case CDATA_SECTION_NODE:
3142 case DOCUMENT_FRAGMENT_NODE:
3143 case DOCUMENT_NODE:
3144 case ENTITY_NODE:
3145 case ENTITY_REFERENCE_NODE:
3146 case NOTATION_NODE:
3147 case TEXT_NODE:
3148 case XPATH_NAMESPACE_NODE:
3149 return false;
3150 case COMMENT_NODE:
3151 case PROCESSING_INSTRUCTION_NODE:
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003152 break;
andersca229761c2007-02-12 23:24:15 +00003153 case DOCUMENT_TYPE_NODE:
3154 numDoctypes++;
3155 break;
3156 case ELEMENT_NODE:
3157 numElements++;
3158 break;
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003159 }
3160 }
3161 } else {
3162 switch (newChild->nodeType()) {
3163 case ATTRIBUTE_NODE:
3164 case CDATA_SECTION_NODE:
3165 case DOCUMENT_FRAGMENT_NODE:
3166 case DOCUMENT_NODE:
3167 case ENTITY_NODE:
3168 case ENTITY_REFERENCE_NODE:
3169 case NOTATION_NODE:
3170 case TEXT_NODE:
3171 case XPATH_NAMESPACE_NODE:
3172 return false;
3173 case COMMENT_NODE:
3174 case PROCESSING_INSTRUCTION_NODE:
3175 return true;
3176 case DOCUMENT_TYPE_NODE:
3177 numDoctypes++;
3178 break;
3179 case ELEMENT_NODE:
3180 numElements++;
3181 break;
andersca229761c2007-02-12 23:24:15 +00003182 }
3183 }
3184
3185 if (numElements > 1 || numDoctypes > 1)
3186 return false;
3187
3188 return true;
3189}
3190
morrita@google.com87288822012-08-31 04:27:31 +00003191PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
darinb9481ed2006-03-20 02:57:59 +00003192{
3193 // Spec says cloning Document nodes is "implementation dependent"
3194 // so we do not support it...
3195 return 0;
3196}
3197
3198StyleSheetList* Document::styleSheets()
3199{
antti@apple.com8a2e6f02012-09-25 04:25:35 +00003200 if (!m_styleSheetList)
3201 m_styleSheetList = StyleSheetList::create(this);
3202 return m_styleSheetList.get();
darinb9481ed2006-03-20 02:57:59 +00003203}
3204
darin4a244792006-05-05 15:22:33 +00003205String Document::preferredStylesheetSet() const
darinb9481ed2006-03-20 02:57:59 +00003206{
antti@apple.come5a88a72012-09-24 22:14:47 +00003207 return m_styleSheetCollection->preferredStylesheetSetName();
darinb9481ed2006-03-20 02:57:59 +00003208}
3209
darin4a244792006-05-05 15:22:33 +00003210String Document::selectedStylesheetSet() const
darinb9481ed2006-03-20 02:57:59 +00003211{
antti@apple.come5a88a72012-09-24 22:14:47 +00003212 return m_styleSheetCollection->selectedStylesheetSetName();
darinb9481ed2006-03-20 02:57:59 +00003213}
3214
3215void Document::setSelectedStylesheetSet(const String& aString)
3216{
antti@apple.come5a88a72012-09-24 22:14:47 +00003217 m_styleSheetCollection->setSelectedStylesheetSetName(aString);
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00003218 styleResolverChanged(DeferRecalcStyle);
darinb9481ed2006-03-20 02:57:59 +00003219}
3220
antti@apple.comef75e9e2012-04-18 18:34:42 +00003221void Document::evaluateMediaQueryList()
3222{
3223 if (m_mediaQueryMatcher)
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00003224 m_mediaQueryMatcher->styleResolverChanged();
antti@apple.comef75e9e2012-04-18 18:34:42 +00003225}
3226
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00003227void Document::styleResolverChanged(StyleResolverUpdateFlag updateFlag)
darinb9481ed2006-03-20 02:57:59 +00003228{
ddkilzer27a28d42007-05-24 01:46:31 +00003229 // Don't bother updating, since we haven't loaded all our style info yet
3230 // and haven't calculated the style selector for the first time.
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00003231 if (!attached() || (!m_didCalculateStyleResolver && !haveStylesheetsLoaded())) {
3232 m_styleResolver.clear();
darinb9481ed2006-03-20 02:57:59 +00003233 return;
antti@apple.com03962272012-01-12 20:21:51 +00003234 }
antti@apple.come5a88a72012-09-24 22:14:47 +00003235 m_didCalculateStyleResolver = true;
darinb9481ed2006-03-20 02:57:59 +00003236
3237#ifdef INSTRUMENT_LAYOUT_SCHEDULING
3238 if (!ownerElement())
3239 printf("Beginning update of style selector at time %d.\n", elapsedTime());
3240#endif
3241
antti@apple.come5a88a72012-09-24 22:14:47 +00003242 DocumentStyleSheetCollection::UpdateFlag styleSheetUpdate = (updateFlag == RecalcStyleIfNeeded)
3243 ? DocumentStyleSheetCollection::OptimizedUpdate
3244 : DocumentStyleSheetCollection::FullUpdate;
3245 bool stylesheetChangeRequiresStyleRecalc = m_styleSheetCollection->updateActiveStyleSheets(styleSheetUpdate);
antti@apple.com8f4b2d62012-01-04 20:03:35 +00003246
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00003247 if (updateFlag == DeferRecalcStyle) {
hyatt@apple.com9e924282010-08-26 19:33:40 +00003248 scheduleForcedStyleRecalc();
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00003249 return;
3250 }
antti@apple.com1b3067c2012-03-02 10:46:55 +00003251
antti@apple.come5a88a72012-09-24 22:14:47 +00003252 if (didLayoutWithPendingStylesheets() && !m_styleSheetCollection->hasPendingSheets()) {
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00003253 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
3254 if (renderer())
3255 renderer()->repaint();
3256 }
3257
antti@apple.com1b3067c2012-03-02 10:46:55 +00003258 if (!stylesheetChangeRequiresStyleRecalc)
3259 return;
3260
cmarrin@apple.comd0121bc2010-04-10 01:00:18 +00003261 // This recalcStyle initiates a new recalc cycle. We need to bracket it to
3262 // make sure animations get the correct update time
simon.fraser@apple.comdbb80872012-05-22 21:17:44 +00003263 {
3264 AnimationUpdateBlock animationUpdateBlock(m_frame ? m_frame->animation() : 0);
3265 recalcStyle(Force);
3266 }
darinb9481ed2006-03-20 02:57:59 +00003267
3268#ifdef INSTRUMENT_LAYOUT_SCHEDULING
3269 if (!ownerElement())
3270 printf("Finished update of style selector at time %d\n", elapsedTime());
3271#endif
3272
3273 if (renderer()) {
darin7e7c8e42007-04-25 01:14:03 +00003274 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
darinb9481ed2006-03-20 02:57:59 +00003275 if (view())
3276 view()->scheduleRelayout();
3277 }
luiz@webkit.orgdb0dd432010-11-22 21:02:27 +00003278
antti@apple.comef75e9e2012-04-18 18:34:42 +00003279 evaluateMediaQueryList();
darinb9481ed2006-03-20 02:57:59 +00003280}
3281
eric@webkit.org876b40e2012-05-09 00:52:08 +00003282void Document::notifySeamlessChildDocumentsOfStylesheetUpdate() const
3283{
3284 // If we're not in a frame yet any potential child documents won't have a StyleResolver to update.
3285 if (!frame())
3286 return;
3287
3288 // Seamless child frames are expected to notify their seamless children recursively, so we only do direct children.
3289 for (Frame* child = frame()->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
3290 Document* childDocument = child->document();
3291 if (childDocument->shouldDisplaySeamlesslyWithParent()) {
3292 ASSERT(childDocument->seamlessParentIFrame()->document() == this);
3293 childDocument->seamlessParentUpdatedStylesheets();
3294 }
3295 }
3296}
3297
darinb9481ed2006-03-20 02:57:59 +00003298void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
3299{
3300 m_hoverNode = newHoverNode;
3301}
3302
3303void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
3304{
3305 m_activeNode = newActiveNode;
3306}
3307
alice.liu@apple.comd7e80fd2007-12-19 22:51:30 +00003308void Document::focusedNodeRemoved()
ggaren7c5851a2006-12-12 22:11:18 +00003309{
ggaren03a0f872006-12-15 03:43:51 +00003310 setFocusedNode(0);
ggaren7c5851a2006-12-12 22:11:18 +00003311}
3312
alice.liu@apple.comd7e80fd2007-12-19 22:51:30 +00003313void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly)
3314{
3315 if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node.
3316 return;
yosin@chromium.orgc58582b2012-09-25 03:26:31 +00003317
3318 Node* focusedNode = node->treeScope()->focusedNode();
3319 if (!focusedNode)
3320 return;
3321
alice.liu@apple.comd7e80fd2007-12-19 22:51:30 +00003322 bool nodeInSubtree = false;
3323 if (amongChildrenOnly)
yosin@chromium.orgc58582b2012-09-25 03:26:31 +00003324 nodeInSubtree = focusedNode->isDescendantOf(node);
alice.liu@apple.comd7e80fd2007-12-19 22:51:30 +00003325 else
yosin@chromium.orgc58582b2012-09-25 03:26:31 +00003326 nodeInSubtree = (focusedNode == node) || focusedNode->isDescendantOf(node);
alice.liu@apple.comd7e80fd2007-12-19 22:51:30 +00003327
3328 if (nodeInSubtree)
3329 document()->focusedNodeRemoved();
3330}
3331
darinb9481ed2006-03-20 02:57:59 +00003332void Document::hoveredNodeDetached(Node* node)
3333{
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003334 if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parentNode())))
darinb9481ed2006-03-20 02:57:59 +00003335 return;
3336
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003337 m_hoverNode = node->parentNode();
darinb9481ed2006-03-20 02:57:59 +00003338 while (m_hoverNode && !m_hoverNode->renderer())
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003339 m_hoverNode = m_hoverNode->parentNode();
darin60e537f52006-11-15 01:29:46 +00003340 if (frame())
3341 frame()->eventHandler()->scheduleHoverStateUpdate();
darinb9481ed2006-03-20 02:57:59 +00003342}
3343
3344void Document::activeChainNodeDetached(Node* node)
3345{
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003346 if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parentNode())))
darinb9481ed2006-03-20 02:57:59 +00003347 return;
3348
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003349 m_activeNode = node->parentNode();
darinb9481ed2006-03-20 02:57:59 +00003350 while (m_activeNode && !m_activeNode->renderer())
dglazkov@chromium.orgc2dd5282010-11-29 21:27:45 +00003351 m_activeNode = m_activeNode->parentNode();
darinb9481ed2006-03-20 02:57:59 +00003352}
3353
jianli@chromium.orgf66b5812012-08-02 00:14:28 +00003354#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(WIDGET_REGION)
darinbe6eb6b2006-09-06 16:23:32 +00003355const Vector<DashboardRegionValue>& Document::dashboardRegions() const
darinb9481ed2006-03-20 02:57:59 +00003356{
3357 return m_dashboardRegions;
3358}
3359
darinbe6eb6b2006-09-06 16:23:32 +00003360void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
darinb9481ed2006-03-20 02:57:59 +00003361{
3362 m_dashboardRegions = regions;
darinbe6eb6b2006-09-06 16:23:32 +00003363 setDashboardRegionsDirty(false);
darinb9481ed2006-03-20 02:57:59 +00003364}
ddkilzer@apple.com8fe65862008-04-29 21:31:09 +00003365#endif
darina6a0caf2007-01-25 00:16:44 +00003366
andersca@apple.comd645ac62011-06-20 20:21:56 +00003367bool Document::setFocusedNode(PassRefPtr<Node> prpNewFocusedNode)
3368{
3369 RefPtr<Node> newFocusedNode = prpNewFocusedNode;
3370
ggaren03a0f872006-12-15 03:43:51 +00003371 // Make sure newFocusedNode is actually in this document
3372 if (newFocusedNode && (newFocusedNode->document() != this))
3373 return true;
darinb9481ed2006-03-20 02:57:59 +00003374
ggaren03a0f872006-12-15 03:43:51 +00003375 if (m_focusedNode == newFocusedNode)
3376 return true;
mitz@apple.com85e88e42008-01-21 02:01:26 +00003377
3378 if (m_inPageCache)
3379 return false;
3380
ggaren03a0f872006-12-15 03:43:51 +00003381 bool focusChangeBlocked = false;
3382 RefPtr<Node> oldFocusedNode = m_focusedNode;
tkent@chromium.org4a11c2f2011-10-05 06:07:51 +00003383 m_focusedNode = 0;
ggaren03a0f872006-12-15 03:43:51 +00003384
3385 // Remove focus from the existing focus node (if any)
morrita@google.com1d498e72012-05-10 14:43:27 +00003386 if (oldFocusedNode) {
morrita@google.comedbd61e2012-05-14 07:49:59 +00003387 ASSERT(!oldFocusedNode->inDetach());
3388
ggaren03a0f872006-12-15 03:43:51 +00003389 if (oldFocusedNode->active())
3390 oldFocusedNode->setActive(false);
3391
3392 oldFocusedNode->setFocus(false);
timothy@apple.com7157c6d2009-12-02 18:34:33 +00003393
ggaren03a0f872006-12-15 03:43:51 +00003394 // Dispatch a change event for text fields or textareas that have been edited
commit-queue@webkit.org5f06da02011-03-05 08:09:39 +00003395 if (oldFocusedNode->isElementNode()) {
3396 Element* element = static_cast<Element*>(oldFocusedNode.get());
3397 if (element->wasChangedSinceLastFormControlChangeEvent())
3398 element->dispatchFormControlChangeEvent();
ggaren03a0f872006-12-15 03:43:51 +00003399 }
3400
3401 // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
hayato@chromium.org91ac1342011-08-18 02:41:10 +00003402 oldFocusedNode->dispatchBlurEvent(newFocusedNode);
ggaren03a0f872006-12-15 03:43:51 +00003403
3404 if (m_focusedNode) {
3405 // handler shifted focus
3406 focusChangeBlocked = true;
3407 newFocusedNode = 0;
3408 }
hyatt@apple.com25d28d12010-03-23 17:53:00 +00003409
hayato@chromium.org3854c5c2011-08-15 11:02:10 +00003410 oldFocusedNode->dispatchFocusOutEvent(eventNames().focusoutEvent, newFocusedNode); // DOM level 3 name for the bubbling blur event.
enrica@apple.combd9026c2010-10-01 20:50:41 +00003411 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
3412 // on it, probably when <rdar://problem/8503958> is resolved.
hayato@chromium.org3854c5c2011-08-15 11:02:10 +00003413 oldFocusedNode->dispatchFocusOutEvent(eventNames().DOMFocusOutEvent, newFocusedNode); // DOM level 2 name for compatibility.
hyatt@apple.com25d28d12010-03-23 17:53:00 +00003414
ggaren03a0f872006-12-15 03:43:51 +00003415 if (m_focusedNode) {
3416 // handler shifted focus
3417 focusChangeBlocked = true;
3418 newFocusedNode = 0;
3419 }
darin@apple.com6f6b5be2009-08-17 17:03:58 +00003420 if (oldFocusedNode == this && oldFocusedNode->hasOneRef())
ggaren03a0f872006-12-15 03:43:51 +00003421 return true;
3422
commit-queue@webkit.org5f402932012-05-11 20:09:13 +00003423 if (oldFocusedNode->isRootEditableElement())
ggaren03a0f872006-12-15 03:43:51 +00003424 frame()->editor()->didEndEditing();
eric@webkit.org754029e2010-05-05 16:22:05 +00003425
3426 if (view()) {
3427 Widget* oldWidget = widgetForNode(oldFocusedNode.get());
3428 if (oldWidget)
3429 oldWidget->setFocus(false);
3430 else
3431 view()->setFocus(false);
3432 }
tkent@chromium.org4a11c2f2011-10-05 06:07:51 +00003433 }
ggaren03a0f872006-12-15 03:43:51 +00003434
3435 if (newFocusedNode) {
commit-queue@webkit.org5f402932012-05-11 20:09:13 +00003436 if (newFocusedNode->isRootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
ggaren03a0f872006-12-15 03:43:51 +00003437 // delegate blocks focus change
3438 focusChangeBlocked = true;
3439 goto SetFocusedNodeDone;
3440 }
3441 // Set focus on the new node
andersca@apple.comd645ac62011-06-20 20:21:56 +00003442 m_focusedNode = newFocusedNode;
ggaren03a0f872006-12-15 03:43:51 +00003443
3444 // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
hayato@chromium.org91ac1342011-08-18 02:41:10 +00003445 m_focusedNode->dispatchFocusEvent(oldFocusedNode);
ggaren03a0f872006-12-15 03:43:51 +00003446
3447 if (m_focusedNode != newFocusedNode) {
3448 // handler shifted focus
3449 focusChangeBlocked = true;
3450 goto SetFocusedNodeDone;
3451 }
hyatt@apple.com25d28d12010-03-23 17:53:00 +00003452
hayato@chromium.org3854c5c2011-08-15 11:02:10 +00003453 m_focusedNode->dispatchFocusInEvent(eventNames().focusinEvent, oldFocusedNode); // DOM level 3 bubbling focus event.
hayato@chromium.org0159d532012-01-24 01:21:42 +00003454
3455 if (m_focusedNode != newFocusedNode) {
3456 // handler shifted focus
3457 focusChangeBlocked = true;
3458 goto SetFocusedNodeDone;
3459 }
3460
enrica@apple.combd9026c2010-10-01 20:50:41 +00003461 // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends
hayato@chromium.org3854c5c2011-08-15 11:02:10 +00003462 // on it, probably when <rdar://problem/8503958> is m.
3463 m_focusedNode->dispatchFocusInEvent(eventNames().DOMFocusInEvent, oldFocusedNode); // DOM level 2 for compatibility.
hyatt@apple.com25d28d12010-03-23 17:53:00 +00003464
ggaren03a0f872006-12-15 03:43:51 +00003465 if (m_focusedNode != newFocusedNode) {
3466 // handler shifted focus
3467 focusChangeBlocked = true;
3468 goto SetFocusedNodeDone;
3469 }
eric@webkit.org754029e2010-05-05 16:22:05 +00003470 m_focusedNode->setFocus(true);
hyatt5e941172007-02-13 04:49:26 +00003471
commit-queue@webkit.org5f402932012-05-11 20:09:13 +00003472 if (m_focusedNode->isRootEditableElement())
weinig28ce8732007-04-19 14:47:21 +00003473 frame()->editor()->didBeginEditing();
3474
ggaren03a0f872006-12-15 03:43:51 +00003475 // eww, I suck. set the qt focus correctly
3476 // ### find a better place in the code for this
3477 if (view()) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003478 Widget* focusWidget = widgetForNode(m_focusedNode.get());
ggaren03a0f872006-12-15 03:43:51 +00003479 if (focusWidget) {
3480 // Make sure a widget has the right size before giving it focus.
3481 // Otherwise, we are testing edge cases of the Widget code.
3482 // Specifically, in WebCore this does not work well for text fields.
3483 updateLayout();
3484 // Re-get the widget in case updating the layout changed things.
3485 focusWidget = widgetForNode(m_focusedNode.get());
3486 }
3487 if (focusWidget)
eric@webkit.org754029e2010-05-05 16:22:05 +00003488 focusWidget->setFocus(true);
ggaren03a0f872006-12-15 03:43:51 +00003489 else
eric@webkit.org754029e2010-05-05 16:22:05 +00003490 view()->setFocus(true);
ggaren03a0f872006-12-15 03:43:51 +00003491 }
ddkilzer@apple.com9c4dacc2009-07-11 05:36:29 +00003492 }
ggaren03a0f872006-12-15 03:43:51 +00003493
commit-queue@webkit.org666227b2010-09-24 07:51:48 +00003494#if PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM)
dmazzoni@google.comcfbd0dd2012-08-15 21:31:35 +00003495 if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
3496 axObjectCache()->handleFocusedUIElementChanged(oldFocusedNode.get(), newFocusedNode.get());
ggaren03a0f872006-12-15 03:43:51 +00003497#endif
levin@chromium.orgec604422009-10-30 20:59:46 +00003498 if (!focusChangeBlocked)
3499 page()->chrome()->focusedNodeChanged(m_focusedNode.get());
ggaren03a0f872006-12-15 03:43:51 +00003500
3501SetFocusedNodeDone:
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00003502 updateStyleIfNeeded();
ggaren03a0f872006-12-15 03:43:51 +00003503 return !focusChangeBlocked;
adele@apple.com3b8816e2009-04-03 00:39:18 +00003504}
3505
3506void Document::getFocusableNodes(Vector<RefPtr<Node> >& nodes)
3507{
3508 updateLayout();
3509
3510 for (Node* node = firstChild(); node; node = node->traverseNextNode()) {
3511 if (node->isFocusable())
3512 nodes.append(node);
3513 }
3514}
ggaren03a0f872006-12-15 03:43:51 +00003515
darin@apple.come8c3a2a2009-02-02 17:29:54 +00003516void Document::setCSSTarget(Element* n)
darinb9481ed2006-03-20 02:57:59 +00003517{
3518 if (m_cssTarget)
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00003519 m_cssTarget->setNeedsStyleRecalc();
darinb9481ed2006-03-20 02:57:59 +00003520 m_cssTarget = n;
3521 if (n)
hyatt@apple.comf6d72f32009-04-10 00:05:02 +00003522 n->setNeedsStyleRecalc();
darinb9481ed2006-03-20 02:57:59 +00003523}
3524
rniwa@webkit.orgf57f8e02012-07-13 19:48:40 +00003525void Document::registerNodeListCache(DynamicNodeListCacheBase* list)
rniwa@webkit.orgfdcdadf2012-06-14 22:38:41 +00003526{
rniwa@webkit.org7f9d0ef2012-07-21 01:03:17 +00003527 if (list->type() != NodeListCollectionType)
rniwa@webkit.orgf57f8e02012-07-13 19:48:40 +00003528 m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
3529 m_nodeListCounts[list->invalidationType()]++;
rniwa@webkit.org198f43c2012-07-13 22:44:46 +00003530 if (list->isRootedAtDocument())
rniwa@webkit.orgfc3b7b72012-07-12 20:31:09 +00003531 m_listsInvalidatedAtDocument.add(list);
rniwa@webkit.orgfdcdadf2012-06-14 22:38:41 +00003532}
3533
rniwa@webkit.orgf57f8e02012-07-13 19:48:40 +00003534void Document::unregisterNodeListCache(DynamicNodeListCacheBase* list)
rniwa@webkit.orgfdcdadf2012-06-14 22:38:41 +00003535{
rniwa@webkit.org7f9d0ef2012-07-21 01:03:17 +00003536 if (list->type() != NodeListCollectionType)
rniwa@webkit.orgf57f8e02012-07-13 19:48:40 +00003537 m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
3538 m_nodeListCounts[list->invalidationType()]--;
rniwa@webkit.org198f43c2012-07-13 22:44:46 +00003539 if (list->isRootedAtDocument()) {
rniwa@webkit.orgfc3b7b72012-07-12 20:31:09 +00003540 ASSERT(m_listsInvalidatedAtDocument.contains(list));
3541 m_listsInvalidatedAtDocument.remove(list);
3542 }
3543}
3544
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003545void Document::attachNodeIterator(NodeIterator* ni)
darinb9481ed2006-03-20 02:57:59 +00003546{
andersca202e8652006-11-18 05:57:13 +00003547 m_nodeIterators.add(ni);
darinb9481ed2006-03-20 02:57:59 +00003548}
3549
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003550void Document::detachNodeIterator(NodeIterator* ni)
darinb9481ed2006-03-20 02:57:59 +00003551{
ap@apple.com3f3f4a12010-09-23 21:09:17 +00003552 // The node iterator can be detached without having been attached if its root node didn't have a document
3553 // when the iterator was created, but has it now.
darinb9481ed2006-03-20 02:57:59 +00003554 m_nodeIterators.remove(ni);
3555}
3556
inferno@chromium.orgb0f943f2010-12-08 23:31:04 +00003557void Document::moveNodeIteratorsToNewDocument(Node* node, Document* newDocument)
3558{
3559 HashSet<NodeIterator*> nodeIteratorsList = m_nodeIterators;
3560 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = nodeIteratorsList.end();
3561 for (HashSet<NodeIterator*>::const_iterator it = nodeIteratorsList.begin(); it != nodeIteratorsEnd; ++it) {
inferno@chromium.orgfd8e0062010-12-09 17:51:07 +00003562 if ((*it)->root() == node) {
inferno@chromium.orgb0f943f2010-12-08 23:31:04 +00003563 detachNodeIterator(*it);
3564 newDocument->attachNodeIterator(*it);
3565 }
3566 }
3567}
3568
rniwa@webkit.org941f8152011-12-09 05:26:58 +00003569void Document::updateRangesAfterChildrenChanged(ContainerNode* container)
darinb9481ed2006-03-20 02:57:59 +00003570{
eric@webkit.org7c632162012-06-29 07:15:44 +00003571 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003572 HashSet<Range*>::const_iterator end = m_ranges.end();
3573 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3574 (*it)->nodeChildrenChanged(container);
3575 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003576}
andersca202e8652006-11-18 05:57:13 +00003577
ap@apple.com748d5222010-05-10 22:13:36 +00003578void Document::nodeChildrenWillBeRemoved(ContainerNode* container)
3579{
eric@webkit.org7c632162012-06-29 07:15:44 +00003580 if (!m_ranges.isEmpty()) {
ap@apple.com748d5222010-05-10 22:13:36 +00003581 HashSet<Range*>::const_iterator end = m_ranges.end();
3582 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3583 (*it)->nodeChildrenWillBeRemoved(container);
3584 }
3585
3586 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3587 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it) {
3588 for (Node* n = container->firstChild(); n; n = n->nextSibling())
3589 (*it)->nodeWillBeRemoved(n);
3590 }
3591
3592 if (Frame* frame = this->frame()) {
3593 for (Node* n = container->firstChild(); n; n = n->nextSibling()) {
rniwa@webkit.org91cc0702011-05-13 21:35:06 +00003594 frame->eventHandler()->nodeWillBeRemoved(n);
ap@apple.com748d5222010-05-10 22:13:36 +00003595 frame->selection()->nodeWillBeRemoved(n);
darin@apple.comb17ec2f2010-09-10 22:06:47 +00003596 frame->page()->dragCaretController()->nodeWillBeRemoved(n);
ap@apple.com748d5222010-05-10 22:13:36 +00003597 }
3598 }
3599}
3600
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003601void Document::nodeWillBeRemoved(Node* n)
3602{
3603 HashSet<NodeIterator*>::const_iterator nodeIteratorsEnd = m_nodeIterators.end();
3604 for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it)
3605 (*it)->nodeWillBeRemoved(n);
3606
eric@webkit.org7c632162012-06-29 07:15:44 +00003607 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003608 HashSet<Range*>::const_iterator rangesEnd = m_ranges.end();
3609 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it)
3610 (*it)->nodeWillBeRemoved(n);
3611 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003612
3613 if (Frame* frame = this->frame()) {
rniwa@webkit.org91cc0702011-05-13 21:35:06 +00003614 frame->eventHandler()->nodeWillBeRemoved(n);
darin@apple.com60d3e9f2008-06-16 06:13:02 +00003615 frame->selection()->nodeWillBeRemoved(n);
darin@apple.comb17ec2f2010-09-10 22:06:47 +00003616 frame->page()->dragCaretController()->nodeWillBeRemoved(n);
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003617 }
3618}
3619
3620void Document::textInserted(Node* text, unsigned offset, unsigned length)
3621{
eric@webkit.org7c632162012-06-29 07:15:44 +00003622 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003623 HashSet<Range*>::const_iterator end = m_ranges.end();
3624 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3625 (*it)->textInserted(text, offset, length);
3626 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003627
3628 // Update the markers for spelling and grammar checking.
dbates@webkit.org858331b2010-08-22 21:41:37 +00003629 m_markers->shiftMarkers(text, offset, length);
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003630}
3631
3632void Document::textRemoved(Node* text, unsigned offset, unsigned length)
3633{
eric@webkit.org7c632162012-06-29 07:15:44 +00003634 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003635 HashSet<Range*>::const_iterator end = m_ranges.end();
3636 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3637 (*it)->textRemoved(text, offset, length);
3638 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003639
3640 // Update the markers for spelling and grammar checking.
dbates@webkit.org858331b2010-08-22 21:41:37 +00003641 m_markers->removeMarkers(text, offset, length);
3642 m_markers->shiftMarkers(text, offset + length, 0 - length);
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003643}
3644
3645void Document::textNodesMerged(Text* oldNode, unsigned offset)
3646{
eric@webkit.org7c632162012-06-29 07:15:44 +00003647 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003648 NodeWithIndex oldNodeWithIndex(oldNode);
3649 HashSet<Range*>::const_iterator end = m_ranges.end();
3650 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3651 (*it)->textNodesMerged(oldNodeWithIndex, offset);
3652 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003653
3654 // FIXME: This should update markers for spelling and grammar checking.
3655}
3656
3657void Document::textNodeSplit(Text* oldNode)
3658{
eric@webkit.org7c632162012-06-29 07:15:44 +00003659 if (!m_ranges.isEmpty()) {
justin.garcia@apple.com692743d2008-05-05 22:50:56 +00003660 HashSet<Range*>::const_iterator end = m_ranges.end();
3661 for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
3662 (*it)->textNodeSplit(oldNode);
3663 }
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003664
3665 // FIXME: This should update markers for spelling and grammar checking.
darinb9481ed2006-03-20 02:57:59 +00003666}
3667
abarth@webkit.org23ea90a2012-08-14 19:47:59 +00003668void Document::createDOMWindow()
darinb9481ed2006-03-20 02:57:59 +00003669{
abarth@webkit.org23ea90a2012-08-14 19:47:59 +00003670 ASSERT(m_frame);
3671 ASSERT(!m_domWindow);
ap@webkit.org142736a2009-05-19 18:14:51 +00003672
abarth@webkit.org23ea90a2012-08-14 19:47:59 +00003673 m_domWindow = DOMWindow::create(this);
ap@webkit.org142736a2009-05-19 18:14:51 +00003674
abarth@webkit.org23ea90a2012-08-14 19:47:59 +00003675 ASSERT(m_domWindow->document() == this);
3676 ASSERT(m_domWindow->frame() == m_frame);
3677}
3678
3679void Document::takeDOMWindowFrom(Document* document)
3680{
3681 ASSERT(m_frame);
3682 ASSERT(!m_domWindow);
3683 ASSERT(document->domWindow());
3684
3685 m_domWindow = document->m_domWindow.release();
3686 m_domWindow->didSecureTransitionTo(this);
3687
3688 ASSERT(m_domWindow->document() == this);
3689 ASSERT(m_domWindow->frame() == m_frame);
darinb9481ed2006-03-20 02:57:59 +00003690}
3691
weinig@apple.comf23f7712009-04-27 23:33:57 +00003692void Document::setWindowAttributeEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener)
3693{
3694 DOMWindow* domWindow = this->domWindow();
3695 if (!domWindow)
3696 return;
3697 domWindow->setAttributeEventListener(eventType, listener);
3698}
3699
weinig@apple.com0ce8f4e2009-06-22 18:32:08 +00003700EventListener* Document::getWindowAttributeEventListener(const AtomicString& eventType)
3701{
3702 DOMWindow* domWindow = this->domWindow();
3703 if (!domWindow)
3704 return 0;
3705 return domWindow->getAttributeEventListener(eventType);
3706}
3707
ggaren@apple.com521f64b2009-09-24 05:53:23 +00003708void Document::dispatchWindowEvent(PassRefPtr<Event> event, PassRefPtr<EventTarget> target)
weinig@apple.com6dfb60c2009-05-31 00:58:06 +00003709{
rniwa@webkit.org61322a12012-10-01 22:24:20 +00003710 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
weinig@apple.com6dfb60c2009-05-31 00:58:06 +00003711 DOMWindow* domWindow = this->domWindow();
3712 if (!domWindow)
3713 return;
ggaren@apple.com521f64b2009-09-24 05:53:23 +00003714 domWindow->dispatchEvent(event, target);
weinig@apple.com6dfb60c2009-05-31 00:58:06 +00003715}
3716
ggaren@apple.com521f64b2009-09-24 05:53:23 +00003717void Document::dispatchWindowLoadEvent()
weinig@apple.comf23f7712009-04-27 23:33:57 +00003718{
rniwa@webkit.org61322a12012-10-01 22:24:20 +00003719 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
weinig@apple.comf23f7712009-04-27 23:33:57 +00003720 DOMWindow* domWindow = this->domWindow();
3721 if (!domWindow)
3722 return;
3723 domWindow->dispatchLoadEvent();
japhet@chromium.org4fdf46f2011-07-06 17:59:59 +00003724 m_loadEventFinished = true;
weinig@apple.comf23f7712009-04-27 23:33:57 +00003725}
3726
mihaip@chromium.orgb042a702010-12-14 22:52:24 +00003727void Document::enqueueWindowEvent(PassRefPtr<Event> event)
jorlow@chromium.orgee1d4762010-01-26 06:23:35 +00003728{
mihaip@chromium.orgb042a702010-12-14 22:52:24 +00003729 event->setTarget(domWindow());
3730 m_eventQueue->enqueueEvent(event);
jorlow@chromium.orgee1d4762010-01-26 06:23:35 +00003731}
3732
rniwa@webkit.org6d5a87e2011-02-21 11:24:41 +00003733void Document::enqueueDocumentEvent(PassRefPtr<Event> event)
3734{
3735 event->setTarget(this);
3736 m_eventQueue->enqueueEvent(event);
3737}
3738
weinig@apple.com4e70ed32008-02-18 00:22:21 +00003739PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00003740{
abarth@webkit.org08feba42011-10-20 04:50:14 +00003741 RefPtr<Event> event = EventFactory::create(eventType);
abarth@webkit.orgb4fefb82010-04-03 07:05:55 +00003742 if (event)
abarth@webkit.org0e7ddb42009-10-20 01:19:01 +00003743 return event.release();
abarth@webkit.orgb4fefb82010-04-03 07:05:55 +00003744
darinb9481ed2006-03-20 02:57:59 +00003745 ec = NOT_SUPPORTED_ERR;
3746 return 0;
3747}
3748
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003749void Document::addMutationEventListenerTypeIfEnabled(ListenerType listenerType)
3750{
3751 if (ContextFeatures::mutationEventsEnabled(this))
3752 addListenerType(listenerType);
3753}
3754
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003755void Document::addListenerTypeIfNeeded(const AtomicString& eventType)
3756{
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003757 if (eventType == eventNames().DOMSubtreeModifiedEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003758 addMutationEventListenerTypeIfEnabled(DOMSUBTREEMODIFIED_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003759 else if (eventType == eventNames().DOMNodeInsertedEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003760 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTED_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003761 else if (eventType == eventNames().DOMNodeRemovedEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003762 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVED_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003763 else if (eventType == eventNames().DOMNodeRemovedFromDocumentEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003764 addMutationEventListenerTypeIfEnabled(DOMNODEREMOVEDFROMDOCUMENT_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003765 else if (eventType == eventNames().DOMNodeInsertedIntoDocumentEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003766 addMutationEventListenerTypeIfEnabled(DOMNODEINSERTEDINTODOCUMENT_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003767 else if (eventType == eventNames().DOMCharacterDataModifiedEvent)
adamk@chromium.orgfdf63462012-08-21 01:14:51 +00003768 addMutationEventListenerTypeIfEnabled(DOMCHARACTERDATAMODIFIED_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003769 else if (eventType == eventNames().overflowchangedEvent)
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003770 addListenerType(OVERFLOWCHANGED_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003771 else if (eventType == eventNames().webkitAnimationStartEvent)
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003772 addListenerType(ANIMATIONSTART_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003773 else if (eventType == eventNames().webkitAnimationEndEvent)
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003774 addListenerType(ANIMATIONEND_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003775 else if (eventType == eventNames().webkitAnimationIterationEvent)
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003776 addListenerType(ANIMATIONITERATION_LISTENER);
ap@webkit.orgc5e3f1b2008-11-04 10:46:13 +00003777 else if (eventType == eventNames().webkitTransitionEndEvent)
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003778 addListenerType(TRANSITIONEND_LISTENER);
hyatt@apple.comf10dc6b2009-10-09 17:03:48 +00003779 else if (eventType == eventNames().beforeloadEvent)
3780 addListenerType(BEFORELOAD_LISTENER);
simon.fraser@apple.com5e4454c2011-06-15 23:02:48 +00003781 else if (eventType == eventNames().scrollEvent)
3782 addListenerType(SCROLL_LISTENER);
zimmermann@webkit.org97c71082008-09-24 00:23:28 +00003783}
3784
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003785CSSStyleDeclaration* Document::getOverrideStyle(Element*, const String&)
darinb9481ed2006-03-20 02:57:59 +00003786{
darin@apple.comf28fa1b2008-03-15 17:26:28 +00003787 return 0;
darinb9481ed2006-03-20 02:57:59 +00003788}
3789
simon.fraser@apple.combab14a92010-07-07 20:04:32 +00003790HTMLFrameOwnerElement* Document::ownerElement() const
darinb9481ed2006-03-20 02:57:59 +00003791{
3792 if (!frame())
3793 return 0;
3794 return frame()->ownerElement();
3795}
3796
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003797String Document::cookie(ExceptionCode& ec) const
oliver9119a9c2007-10-12 15:13:16 +00003798{
commit-queue@webkit.orgc8870db2012-06-20 23:49:53 +00003799 if (page() && !page()->settings()->cookieEnabled())
mitz@apple.comb7f88482008-10-31 23:35:00 +00003800 return String();
3801
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003802 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3803 // INVALID_STATE_ERR exception on getting if the Document has no
3804 // browsing context.
3805
abarth@webkit.org907caeb2010-01-10 08:10:00 +00003806 if (!securityOrigin()->canAccessCookies()) {
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003807 ec = SECURITY_ERR;
3808 return String();
3809 }
3810
adele@apple.comd4ac2992008-12-29 21:42:33 +00003811 KURL cookieURL = this->cookieURL();
3812 if (cookieURL.isEmpty())
3813 return String();
3814
3815 return cookies(this, cookieURL);
oliver9119a9c2007-10-12 15:13:16 +00003816}
3817
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003818void Document::setCookie(const String& value, ExceptionCode& ec)
oliver9119a9c2007-10-12 15:13:16 +00003819{
commit-queue@webkit.orgc8870db2012-06-20 23:49:53 +00003820 if (page() && !page()->settings()->cookieEnabled())
mitz@apple.comb7f88482008-10-31 23:35:00 +00003821 return;
3822
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003823 // FIXME: The HTML5 DOM spec states that this attribute can raise an
3824 // INVALID_STATE_ERR exception on setting if the Document has no
3825 // browsing context.
3826
abarth@webkit.org907caeb2010-01-10 08:10:00 +00003827 if (!securityOrigin()->canAccessCookies()) {
abarth@webkit.orgb8a10552009-12-02 02:40:35 +00003828 ec = SECURITY_ERR;
3829 return;
3830 }
3831
adele@apple.comd4ac2992008-12-29 21:42:33 +00003832 KURL cookieURL = this->cookieURL();
3833 if (cookieURL.isEmpty())
3834 return;
3835
abarth@webkit.org67646792009-05-22 16:45:32 +00003836 setCookies(this, cookieURL, value);
oliver9119a9c2007-10-12 15:13:16 +00003837}
3838
darinb9481ed2006-03-20 02:57:59 +00003839String Document::referrer() const
3840{
3841 if (frame())
ggarenb2497d82006-10-28 01:22:13 +00003842 return frame()->loader()->referrer();
darinb9481ed2006-03-20 02:57:59 +00003843 return String();
3844}
3845
3846String Document::domain() const
3847{
ap@webkit.org0497fce2008-12-02 08:49:06 +00003848 return securityOrigin()->domain();
darinb9481ed2006-03-20 02:57:59 +00003849}
3850
eric@webkit.orge13621e2009-09-25 17:53:43 +00003851void Document::setDomain(const String& newDomain, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00003852{
abarth@webkit.org8e056b02011-11-08 01:37:47 +00003853 if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) {
aroben@apple.com9ca1e9e2010-01-18 21:26:39 +00003854 ec = SECURITY_ERR;
3855 return;
3856 }
3857
darinb9481ed2006-03-20 02:57:59 +00003858 // Both NS and IE specify that changing the domain is only allowed when
3859 // the new domain is a suffix of the old domain.
weinigc1cac712007-07-30 18:29:29 +00003860
weinig@apple.comd8788682007-11-27 01:52:43 +00003861 // FIXME: We should add logging indicating why a domain was not allowed.
3862
3863 // If the new domain is the same as the old domain, still call
ap@webkit.org0497fce2008-12-02 08:49:06 +00003864 // securityOrigin()->setDomainForDOM. This will change the
weinig@apple.comd8788682007-11-27 01:52:43 +00003865 // security check behavior. For example, if a page loaded on port 8000
3866 // assigns its current domain using document.domain, the page will
3867 // allow other pages loaded on different ports in the same domain that
3868 // have also assigned to access this page.
weinig@apple.com64321612007-12-20 22:39:51 +00003869 if (equalIgnoringCase(domain(), newDomain)) {
ap@webkit.org0497fce2008-12-02 08:49:06 +00003870 securityOrigin()->setDomainFromDOM(newDomain);
abarth@webkit.org24d63ef2008-12-10 06:48:36 +00003871 if (m_frame)
3872 m_frame->script()->updateSecurityOrigin();
weinig@apple.comd8788682007-11-27 01:52:43 +00003873 return;
3874 }
weinigc1cac712007-07-30 18:29:29 +00003875
weinig@apple.com64321612007-12-20 22:39:51 +00003876 int oldLength = domain().length();
darinb9481ed2006-03-20 02:57:59 +00003877 int newLength = newDomain.length();
weinig@apple.com64321612007-12-20 22:39:51 +00003878 // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14)
eric@webkit.orge13621e2009-09-25 17:53:43 +00003879 if (newLength >= oldLength) {
3880 ec = SECURITY_ERR;
weinig@apple.comd8788682007-11-27 01:52:43 +00003881 return;
eric@webkit.orge13621e2009-09-25 17:53:43 +00003882 }
weinige06430a2007-10-19 20:53:22 +00003883
darin@apple.com4db8bb12008-01-13 19:19:41 +00003884 String test = domain();
weinig@apple.comd8788682007-11-27 01:52:43 +00003885 // Check that it's a subdomain, not e.g. "ebkit.org"
eric@webkit.orge13621e2009-09-25 17:53:43 +00003886 if (test[oldLength - newLength - 1] != '.') {
3887 ec = SECURITY_ERR;
weinig@apple.comd8788682007-11-27 01:52:43 +00003888 return;
eric@webkit.orge13621e2009-09-25 17:53:43 +00003889 }
weinig@apple.comd8788682007-11-27 01:52:43 +00003890
weinig@apple.com64321612007-12-20 22:39:51 +00003891 // Now test is "webkit.org" from domain()
weinig@apple.comd8788682007-11-27 01:52:43 +00003892 // and we check that it's the same thing as newDomain
3893 test.remove(0, oldLength - newLength);
eric@webkit.orge13621e2009-09-25 17:53:43 +00003894 if (test != newDomain) {
3895 ec = SECURITY_ERR;
weinig@apple.comd8788682007-11-27 01:52:43 +00003896 return;
eric@webkit.orge13621e2009-09-25 17:53:43 +00003897 }
weinig@apple.comd8788682007-11-27 01:52:43 +00003898
ap@webkit.org0497fce2008-12-02 08:49:06 +00003899 securityOrigin()->setDomainFromDOM(newDomain);
abarth@webkit.org24d63ef2008-12-10 06:48:36 +00003900 if (m_frame)
3901 m_frame->script()->updateSecurityOrigin();
weinigc1cac712007-07-30 18:29:29 +00003902}
3903
abarth@webkit.org6dbb21c2010-09-14 23:29:38 +00003904// http://www.whatwg.org/specs/web-apps/current-work/#dom-document-lastmodified
oliver9119a9c2007-10-12 15:13:16 +00003905String Document::lastModified() const
3906{
abarth@webkit.org6dbb21c2010-09-14 23:29:38 +00003907 DateComponents date;
3908 bool foundDate = false;
3909 if (m_frame) {
beidson@apple.com197fbd32011-05-31 22:13:06 +00003910 String httpLastModified;
3911 if (DocumentLoader* documentLoader = loader())
3912 httpLastModified = documentLoader->response().httpHeaderField("Last-Modified");
abarth@webkit.org6dbb21c2010-09-14 23:29:38 +00003913 if (!httpLastModified.isEmpty()) {
3914 date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified));
3915 foundDate = true;
3916 }
3917 }
3918 // FIXME: If this document came from the file system, the HTML5
3919 // specificiation tells us to read the last modification date from the file
3920 // system.
3921 if (!foundDate)
3922 date.setMillisecondsSinceEpochForDateTime(currentTimeMS());
3923 return String::format("%02d/%02d/%04d %02d:%02d:%02d", date.month() + 1, date.monthDay(), date.fullYear(), date.hour(), date.minute(), date.second());
oliver9119a9c2007-10-12 15:13:16 +00003924}
3925
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003926static bool isValidNameNonASCII(const UChar* characters, unsigned length)
darinb9481ed2006-03-20 02:57:59 +00003927{
darinb9481ed2006-03-20 02:57:59 +00003928 unsigned i = 0;
3929
3930 UChar32 c;
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003931 U16_NEXT(characters, i, length, c)
darinb9481ed2006-03-20 02:57:59 +00003932 if (!isValidNameStart(c))
3933 return false;
3934
3935 while (i < length) {
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003936 U16_NEXT(characters, i, length, c)
darinb9481ed2006-03-20 02:57:59 +00003937 if (!isValidNamePart(c))
3938 return false;
3939 }
3940
3941 return true;
3942}
3943
commit-queue@webkit.org44da6442011-12-19 08:11:24 +00003944template<typename CharType>
3945static inline bool isValidNameASCII(const CharType* characters, unsigned length)
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003946{
commit-queue@webkit.org44da6442011-12-19 08:11:24 +00003947 CharType c = characters[0];
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003948 if (!(isASCIIAlpha(c) || c == ':' || c == '_'))
3949 return false;
3950
3951 for (unsigned i = 1; i < length; ++i) {
3952 c = characters[i];
3953 if (!(isASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' || c == '.'))
3954 return false;
3955 }
3956
3957 return true;
3958}
3959
3960bool Document::isValidName(const String& name)
3961{
3962 unsigned length = name.length();
3963 if (!length)
3964 return false;
3965
commit-queue@webkit.org44da6442011-12-19 08:11:24 +00003966 const UChar* characters;
3967 if (name.is8Bit()) {
3968 if (isValidNameASCII(name.characters8(), length))
3969 return true;
3970 characters = name.characters();
3971 } else {
3972 characters = name.characters16();
3973 if (isValidNameASCII(characters, length))
3974 return true;
3975 }
3976 return isValidNameNonASCII(characters, length);
darin@apple.coma4fc32d2008-03-25 03:26:02 +00003977}
3978
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00003979bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, String& localName, ExceptionCode& ec)
darinb9481ed2006-03-20 02:57:59 +00003980{
3981 unsigned length = qualifiedName.length();
3982
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00003983 if (!length) {
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00003984 ec = INVALID_CHARACTER_ERR;
darinb9481ed2006-03-20 02:57:59 +00003985 return false;
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00003986 }
darinb9481ed2006-03-20 02:57:59 +00003987
3988 bool nameStart = true;
3989 bool sawColon = false;
3990 int colonPos = 0;
3991
eric@webkit.org87d855b2008-03-10 22:06:44 +00003992 const UChar* s = qualifiedName.characters();
darinb9481ed2006-03-20 02:57:59 +00003993 for (unsigned i = 0; i < length;) {
3994 UChar32 c;
3995 U16_NEXT(s, i, length, c)
3996 if (c == ':') {
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00003997 if (sawColon) {
3998 ec = NAMESPACE_ERR;
darinb9481ed2006-03-20 02:57:59 +00003999 return false; // multiple colons: not allowed
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004000 }
darinb9481ed2006-03-20 02:57:59 +00004001 nameStart = true;
4002 sawColon = true;
4003 colonPos = i - 1;
4004 } else if (nameStart) {
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004005 if (!isValidNameStart(c)) {
4006 ec = INVALID_CHARACTER_ERR;
darinb9481ed2006-03-20 02:57:59 +00004007 return false;
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004008 }
darinb9481ed2006-03-20 02:57:59 +00004009 nameStart = false;
4010 } else {
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004011 if (!isValidNamePart(c)) {
4012 ec = INVALID_CHARACTER_ERR;
darinb9481ed2006-03-20 02:57:59 +00004013 return false;
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004014 }
darinb9481ed2006-03-20 02:57:59 +00004015 }
4016 }
4017
4018 if (!sawColon) {
4019 prefix = String();
darin@apple.com4db8bb12008-01-13 19:19:41 +00004020 localName = qualifiedName;
darinb9481ed2006-03-20 02:57:59 +00004021 } else {
4022 prefix = qualifiedName.substring(0, colonPos);
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004023 if (prefix.isEmpty()) {
4024 ec = NAMESPACE_ERR;
4025 return false;
4026 }
darin@apple.com4db8bb12008-01-13 19:19:41 +00004027 localName = qualifiedName.substring(colonPos + 1);
darinb9481ed2006-03-20 02:57:59 +00004028 }
4029
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004030 if (localName.isEmpty()) {
4031 ec = NAMESPACE_ERR;
4032 return false;
4033 }
4034
darinb9481ed2006-03-20 02:57:59 +00004035 return true;
4036}
4037
darin@apple.com642f5002008-06-07 22:51:37 +00004038void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder)
darinb9481ed2006-03-20 02:57:59 +00004039{
4040 m_decoder = decoder;
4041}
4042
abarth@webkit.orge18d0592012-02-01 04:07:52 +00004043KURL Document::completeURL(const String& url, const KURL& baseURLOverride) const
darinb9481ed2006-03-20 02:57:59 +00004044{
darin@apple.com640fa302008-02-15 05:03:55 +00004045 // Always return a null URL when passed a null string.
4046 // FIXME: Should we change the KURL constructor to have this behavior?
ddkilzer@apple.come9a55042008-12-23 00:00:14 +00004047 // See also [CSS]StyleSheet::completeURL(const String&)
weinig@apple.comc5002662007-12-12 07:26:19 +00004048 if (url.isNull())
darin@apple.com640fa302008-02-15 05:03:55 +00004049 return KURL();
abarth@webkit.orge18d0592012-02-01 04:07:52 +00004050 const KURL& baseURL = ((baseURLOverride.isEmpty() || baseURLOverride == blankURL()) && parentDocument()) ? parentDocument()->baseURL() : baseURLOverride;
darin@apple.com640fa302008-02-15 05:03:55 +00004051 if (!m_decoder)
ddkilzer@apple.coma6df9992009-03-24 21:40:24 +00004052 return KURL(baseURL, url);
4053 return KURL(baseURL, url, m_decoder->encoding());
darinb9481ed2006-03-20 02:57:59 +00004054}
4055
abarth@webkit.orge18d0592012-02-01 04:07:52 +00004056KURL Document::completeURL(const String& url) const
4057{
4058 return completeURL(url, m_baseURL);
4059}
4060
darinb9481ed2006-03-20 02:57:59 +00004061void Document::setInPageCache(bool flag)
4062{
4063 if (m_inPageCache == flag)
4064 return;
4065
4066 m_inPageCache = flag;
bdakin@apple.comc7a8e422011-05-10 22:37:15 +00004067
4068 FrameView* v = view();
darinb9481ed2006-03-20 02:57:59 +00004069 if (flag) {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00004070 ASSERT(!m_savedRenderer);
darinb9481ed2006-03-20 02:57:59 +00004071 m_savedRenderer = renderer();
bdakin@apple.comc7a8e422011-05-10 22:37:15 +00004072 if (v) {
bdakin@apple.comd1b045c2011-04-22 22:10:21 +00004073 v->cacheCurrentScrollPosition();
4074 if (page() && page()->mainFrame() == m_frame)
4075 v->resetScrollbarsAndClearContentsSize();
4076 else
4077 v->resetScrollbars();
4078 }
hyatt@apple.com8dd0d932010-08-26 18:17:59 +00004079 m_styleRecalcTimer.stop();
darinb9481ed2006-03-20 02:57:59 +00004080 } else {
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00004081 ASSERT(!renderer() || renderer() == m_savedRenderer);
eseidelfe326432006-04-25 05:00:39 +00004082 ASSERT(m_renderArena);
darinb9481ed2006-03-20 02:57:59 +00004083 setRenderer(m_savedRenderer);
4084 m_savedRenderer = 0;
luiz@webkit.orge0514c52010-09-24 21:54:25 +00004085
hyatt@apple.com094f41b2009-04-13 17:14:44 +00004086 if (childNeedsStyleRecalc())
4087 scheduleStyleRecalc();
darinb9481ed2006-03-20 02:57:59 +00004088 }
4089}
4090
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004091void Document::documentWillBecomeInactive()
darinb9481ed2006-03-20 02:57:59 +00004092{
simon.fraser@apple.com8f9c77b2009-02-06 17:05:07 +00004093#if USE(ACCELERATED_COMPOSITING)
4094 if (renderer())
4095 renderView()->willMoveOffscreen();
4096#endif
darinb9481ed2006-03-20 02:57:59 +00004097}
4098
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004099void Document::documentWillSuspendForPageCache()
4100{
4101 documentWillBecomeInactive();
4102
4103 HashSet<Element*>::iterator end = m_documentSuspensionCallbackElements.end();
4104 for (HashSet<Element*>::iterator i = m_documentSuspensionCallbackElements.begin(); i != end; ++i)
4105 (*i)->documentWillSuspendForPageCache();
commit-queue@webkit.org7adcbd82012-05-02 13:00:47 +00004106
4107#ifndef NDEBUG
4108 // Clear the update flag to be able to check if the viewport arguments update
4109 // is dispatched, after the document is restored from the page cache.
4110 m_didDispatchViewportPropertiesChanged = false;
4111#endif
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004112}
4113
4114void Document::documentDidResumeFromPageCache()
darinb9481ed2006-03-20 02:57:59 +00004115{
beidson@apple.com343e49b2011-12-12 22:00:31 +00004116 Vector<Element*> elements;
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004117 copyToVector(m_documentSuspensionCallbackElements, elements);
beidson@apple.com343e49b2011-12-12 22:00:31 +00004118 Vector<Element*>::iterator end = elements.end();
4119 for (Vector<Element*>::iterator i = elements.begin(); i != end; ++i)
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004120 (*i)->documentDidResumeFromPageCache();
simon.fraser@apple.com8f9c77b2009-02-06 17:05:07 +00004121
4122#if USE(ACCELERATED_COMPOSITING)
4123 if (renderer())
4124 renderView()->didMoveOnscreen();
4125#endif
ap@apple.com43af8a82010-10-29 17:23:55 +00004126
bdakin@apple.com8a57afc2011-06-15 23:13:23 +00004127 if (FrameView* frameView = view())
4128 frameView->setAnimatorsAreActive();
4129
ap@apple.com43af8a82010-10-29 17:23:55 +00004130 ASSERT(m_frame);
4131 m_frame->loader()->client()->dispatchDidBecomeFrameset(isFrameSet());
darinb9481ed2006-03-20 02:57:59 +00004132}
4133
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004134void Document::registerForPageCacheSuspensionCallbacks(Element* e)
darinb9481ed2006-03-20 02:57:59 +00004135{
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004136 m_documentSuspensionCallbackElements.add(e);
antti76787a82007-10-31 01:03:35 +00004137}
4138
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004139void Document::unregisterForPageCacheSuspensionCallbacks(Element* e)
antti76787a82007-10-31 01:03:35 +00004140{
beidson@apple.coma675a9d2011-12-17 00:32:40 +00004141 m_documentSuspensionCallbackElements.remove(e);
darinb9481ed2006-03-20 02:57:59 +00004142}
4143
mitz@apple.com44d57d42008-11-11 22:45:16 +00004144void Document::mediaVolumeDidChange()
4145{
4146 HashSet<Element*>::iterator end = m_mediaVolumeCallbackElements.end();
4147 for (HashSet<Element*>::iterator i = m_mediaVolumeCallbackElements.begin(); i != end; ++i)
4148 (*i)->mediaVolumeDidChange();
4149}
4150
4151void Document::registerForMediaVolumeCallbacks(Element* e)
4152{
4153 m_mediaVolumeCallbackElements.add(e);
4154}
4155
4156void Document::unregisterForMediaVolumeCallbacks(Element* e)
4157{
4158 m_mediaVolumeCallbackElements.remove(e);
4159}
4160
jpfau@apple.comaaef7312012-09-14 21:30:42 +00004161void Document::storageBlockingStateDidChange()
4162{
4163 if (Settings* settings = this->settings())
4164 securityOrigin()->setStorageBlockingPolicy(settings->storageBlockingPolicy());
4165}
4166
eric.carlson@apple.com98deeaa2011-03-01 20:54:37 +00004167void Document::privateBrowsingStateDidChange()
4168{
4169 HashSet<Element*>::iterator end = m_privateBrowsingStateChangedElements.end();
4170 for (HashSet<Element*>::iterator it = m_privateBrowsingStateChangedElements.begin(); it != end; ++it)
4171 (*it)->privateBrowsingStateDidChange();
4172}
4173
4174void Document::registerForPrivateBrowsingStateChangedCallbacks(Element* e)
4175{
4176 m_privateBrowsingStateChangedElements.add(e);
4177}
4178
4179void Document::unregisterForPrivateBrowsingStateChangedCallbacks(Element* e)
4180{
4181 m_privateBrowsingStateChangedElements.remove(e);
4182}
4183
darinb9481ed2006-03-20 02:57:59 +00004184void Document::setShouldCreateRenderers(bool f)
4185{
4186 m_createRenderers = f;
4187}
4188
4189bool Document::shouldCreateRenderers()
4190{
4191 return m_createRenderers;
4192}
4193
darinb9481ed2006-03-20 02:57:59 +00004194// Support for Javascript execCommand, and related methods
4195
darin@apple.com5377d7d2007-12-11 20:26:56 +00004196static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
darinb9481ed2006-03-20 02:57:59 +00004197{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004198 Frame* frame = document->frame();
4199 if (!frame || frame->document() != document)
4200 return Editor::Command();
simon.fraser@apple.com64487f92010-08-19 17:19:40 +00004201
4202 document->updateStyleIfNeeded();
4203
darin@apple.com5377d7d2007-12-11 20:26:56 +00004204 return frame->editor()->command(commandName,
4205 userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
darinb9481ed2006-03-20 02:57:59 +00004206}
4207
darin@apple.com5377d7d2007-12-11 20:26:56 +00004208bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
darinb9481ed2006-03-20 02:57:59 +00004209{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004210 return command(this, commandName, userInterface).execute(value);
darinb9481ed2006-03-20 02:57:59 +00004211}
4212
darin@apple.com5377d7d2007-12-11 20:26:56 +00004213bool Document::queryCommandEnabled(const String& commandName)
darinb9481ed2006-03-20 02:57:59 +00004214{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004215 return command(this, commandName).isEnabled();
darinb9481ed2006-03-20 02:57:59 +00004216}
4217
darin@apple.com5377d7d2007-12-11 20:26:56 +00004218bool Document::queryCommandIndeterm(const String& commandName)
darinb9481ed2006-03-20 02:57:59 +00004219{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004220 return command(this, commandName).state() == MixedTriState;
darinb9481ed2006-03-20 02:57:59 +00004221}
4222
darin@apple.com5377d7d2007-12-11 20:26:56 +00004223bool Document::queryCommandState(const String& commandName)
darinb9481ed2006-03-20 02:57:59 +00004224{
rniwa@webkit.org5c713d92010-09-27 21:10:54 +00004225 return command(this, commandName).state() == TrueTriState;
darinb9481ed2006-03-20 02:57:59 +00004226}
4227
darin@apple.com5377d7d2007-12-11 20:26:56 +00004228bool Document::queryCommandSupported(const String& commandName)
darinb9481ed2006-03-20 02:57:59 +00004229{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004230 return command(this, commandName).isSupported();
darinb9481ed2006-03-20 02:57:59 +00004231}
4232
darin@apple.com5377d7d2007-12-11 20:26:56 +00004233String Document::queryCommandValue(const String& commandName)
darinb9481ed2006-03-20 02:57:59 +00004234{
darin@apple.com5377d7d2007-12-11 20:26:56 +00004235 return command(this, commandName).value();
darinb9481ed2006-03-20 02:57:59 +00004236}
4237
abarth@webkit.orgd4036052011-06-23 00:39:10 +00004238KURL Document::openSearchDescriptionURL()
4239{
4240 static const char* const openSearchMIMEType = "application/opensearchdescription+xml";
4241 static const char* const openSearchRelation = "search";
4242
4243 // FIXME: Why do only top-level frames have openSearchDescriptionURLs?
4244 if (!frame() || frame()->tree()->parent())
4245 return KURL();
4246
4247 // FIXME: Why do we need to wait for FrameStateComplete?
4248 if (frame()->loader()->state() != FrameStateComplete)
4249 return KURL();
4250
4251 if (!head())
4252 return KURL();
4253
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004254 RefPtr<HTMLCollection> children = head()->children();
rniwa@webkit.orgd50a6652012-06-26 06:29:58 +00004255 for (unsigned i = 0; Node* child = children->item(i); i++) {
darin@apple.comfa0136f2011-10-15 07:59:24 +00004256 if (!child->hasTagName(linkTag))
abarth@webkit.orgd4036052011-06-23 00:39:10 +00004257 continue;
4258 HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(child);
4259 if (!equalIgnoringCase(linkElement->type(), openSearchMIMEType) || !equalIgnoringCase(linkElement->rel(), openSearchRelation))
4260 continue;
4261 if (linkElement->href().isEmpty())
4262 continue;
4263 return linkElement->href();
4264 }
4265
4266 return KURL();
4267}
4268
mjsd2948ef2007-02-26 19:29:04 +00004269#if ENABLE(XSLT)
darinb9481ed2006-03-20 02:57:59 +00004270
4271void Document::applyXSLTransform(ProcessingInstruction* pi)
4272{
andersca@apple.comc442c152008-02-20 01:55:42 +00004273 RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
darin@apple.com3aa89272008-06-15 04:32:16 +00004274 processor->setXSLStyleSheet(static_cast<XSLStyleSheet*>(pi->sheet()));
ap276970c2007-10-29 17:02:51 +00004275 String resultMIMEType;
4276 String newSource;
4277 String resultEncoding;
darinb9481ed2006-03-20 02:57:59 +00004278 if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
4279 return;
4280 // FIXME: If the transform failed we should probably report an error (like Mozilla does).
mjs22f8a1a2007-04-29 07:33:46 +00004281 processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
darinb9481ed2006-03-20 02:57:59 +00004282}
4283
hausmann@webkit.org06b7e552009-09-28 20:11:36 +00004284void Document::setTransformSource(PassOwnPtr<TransformSource> source)
bdashc4bd53a2007-07-12 14:01:41 +00004285{
hausmann@webkit.org06b7e552009-09-28 20:11:36 +00004286 m_transformSource = source;
bdashc4bd53a2007-07-12 14:01:41 +00004287}
4288
darinb9481ed2006-03-20 02:57:59 +00004289#endif
4290
4291void Document::setDesignMode(InheritedBool value)
4292{
4293 m_designMode = value;
commit-queue@webkit.org713aea42011-04-29 00:10:34 +00004294 for (Frame* frame = m_frame; frame && frame->document(); frame = frame->tree()->traverseNext(m_frame))
4295 frame->document()->scheduleForcedStyleRecalc();
darinb9481ed2006-03-20 02:57:59 +00004296}
4297
4298Document::InheritedBool Document::getDesignMode() const
4299{
4300 return m_designMode;
4301}
4302
4303bool Document::inDesignMode() const
4304{
4305 for (const Document* d = this; d; d = d->parentDocument()) {
4306 if (d->m_designMode != inherit)
justing1c9170e2006-07-25 21:06:25 +00004307 return d->m_designMode;
darinb9481ed2006-03-20 02:57:59 +00004308 }
4309 return false;
4310}
4311
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00004312Document* Document::parentDocument() const
darinb9481ed2006-03-20 02:57:59 +00004313{
abarth@webkit.org345dd262010-09-10 22:08:41 +00004314 if (!m_frame)
darinb9481ed2006-03-20 02:57:59 +00004315 return 0;
abarth@webkit.org345dd262010-09-10 22:08:41 +00004316 Frame* parent = m_frame->tree()->parent();
darinb9481ed2006-03-20 02:57:59 +00004317 if (!parent)
4318 return 0;
4319 return parent->document();
4320}
4321
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00004322Document* Document::topDocument() const
darinb9481ed2006-03-20 02:57:59 +00004323{
abarth@webkit.orgf77ca5c2010-08-07 01:30:16 +00004324 Document* doc = const_cast<Document *>(this);
4325 Element* element;
beidsonddbaead2006-12-13 23:34:09 +00004326 while ((element = doc->ownerElement()))
ggarenaa01dc02006-03-29 00:21:31 +00004327 doc = element->document();
darinb9481ed2006-03-20 02:57:59 +00004328
4329 return doc;
4330}
4331
darin@apple.com9a925fa2009-05-04 18:00:34 +00004332PassRefPtr<Attr> Document::createAttribute(const String& name, ExceptionCode& ec)
4333{
4334 return createAttributeNS(String(), name, ec, true);
4335}
4336
jchaffraix@webkit.org17b7c902008-06-02 19:51:32 +00004337PassRefPtr<Attr> Document::createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode& ec, bool shouldIgnoreNamespaceChecks)
darinb9481ed2006-03-20 02:57:59 +00004338{
eric@webkit.org4e5ae832008-03-22 09:49:58 +00004339 String prefix, localName;
eric@webkit.orgdc1386a2008-03-22 09:50:54 +00004340 if (!parseQualifiedName(qualifiedName, prefix, localName, ec))
eric@webkit.org4e5ae832008-03-22 09:49:58 +00004341 return 0;
eric@webkit.org4e5ae832008-03-22 09:49:58 +00004342
4343 QualifiedName qName(prefix, localName, namespaceURI);
kmccullough@apple.com9aa2a5b2008-02-06 22:03:08 +00004344
abarth@webkit.org427e9f12012-01-19 08:31:13 +00004345 if (!shouldIgnoreNamespaceChecks && !hasValidNamespaceForAttributes(qName)) {
eric@webkit.org4e5ae832008-03-22 09:49:58 +00004346 ec = NAMESPACE_ERR;
eric@webkit.org63d461e2008-02-03 23:46:58 +00004347 return 0;
4348 }
eric@webkit.org4e5ae832008-03-22 09:49:58 +00004349
kling@webkit.orge3f8e9d2012-04-23 05:40:02 +00004350 return Attr::create(this, qName, emptyString());
darinb9481ed2006-03-20 02:57:59 +00004351}
4352
mjsd2948ef2007-02-26 19:29:04 +00004353#if ENABLE(SVG)
darinb9481ed2006-03-20 02:57:59 +00004354const SVGDocumentExtensions* Document::svgExtensions()
4355{
zecke@webkit.orgf3834492008-09-20 14:23:55 +00004356 return m_svgExtensions.get();
darinb9481ed2006-03-20 02:57:59 +00004357}
4358
4359SVGDocumentExtensions* Document::accessSVGExtensions()
4360{
4361 if (!m_svgExtensions)
darin@apple.com69b3ef42010-08-31 17:08:40 +00004362 m_svgExtensions = adoptPtr(new SVGDocumentExtensions(this));
zecke@webkit.orgf3834492008-09-20 14:23:55 +00004363 return m_svgExtensions.get();
darinb9481ed2006-03-20 02:57:59 +00004364}
commit-queue@webkit.org3c4e1242010-09-23 21:36:18 +00004365
4366bool Document::hasSVGRootNode() const
4367{
4368 return documentElement() && documentElement()->hasTagName(SVGNames::svgTag);
4369}
darinb9481ed2006-03-20 02:57:59 +00004370#endif
4371
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004372// FIXME: This caching mechanism should be merged that of DynamicNodeList in NodeRareData.
4373PassRefPtr<HTMLCollection> Document::cachedCollection(CollectionType type)
kling@webkit.org3e527e92011-12-16 23:11:11 +00004374{
kling@webkit.org66299d62011-12-16 23:45:29 +00004375 ASSERT(static_cast<unsigned>(type) < NumUnnamedDocumentCachedTypes);
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004376 if (m_collections[type])
4377 return m_collections[type];
4378
4379 RefPtr<HTMLCollection> collection;
4380 if (type == DocAll)
4381 collection = HTMLAllCollection::create(this);
4382 else
4383 collection = HTMLCollection::create(this, type);
4384 m_collections[type] = collection.get();
4385
4386 return collection.release();
kling@webkit.org3e527e92011-12-16 23:11:11 +00004387}
4388
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004389void Document::removeCachedHTMLCollection(HTMLCollection* collection, CollectionType type)
4390{
4391 ASSERT_UNUSED(collection, m_collections[type] == collection);
4392 m_collections[type] = 0;
4393}
4394
4395PassRefPtr<HTMLCollection> Document::images()
darinb9481ed2006-03-20 02:57:59 +00004396{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004397 return cachedCollection(DocImages);
darinb9481ed2006-03-20 02:57:59 +00004398}
4399
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004400PassRefPtr<HTMLCollection> Document::applets()
darinb9481ed2006-03-20 02:57:59 +00004401{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004402 return cachedCollection(DocApplets);
darinb9481ed2006-03-20 02:57:59 +00004403}
4404
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004405PassRefPtr<HTMLCollection> Document::embeds()
darinb9481ed2006-03-20 02:57:59 +00004406{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004407 return cachedCollection(DocEmbeds);
darinb9481ed2006-03-20 02:57:59 +00004408}
4409
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004410PassRefPtr<HTMLCollection> Document::plugins()
weinig661a37f2007-05-23 23:00:20 +00004411{
4412 // This is an alias for embeds() required for the JS DOM bindings.
kling@webkit.org3e527e92011-12-16 23:11:11 +00004413 return cachedCollection(DocEmbeds);
weinig661a37f2007-05-23 23:00:20 +00004414}
4415
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004416PassRefPtr<HTMLCollection> Document::objects()
darinb9481ed2006-03-20 02:57:59 +00004417{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004418 return cachedCollection(DocObjects);
darinb9481ed2006-03-20 02:57:59 +00004419}
4420
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004421PassRefPtr<HTMLCollection> Document::scripts()
andersca1d0b3772006-05-24 19:26:09 +00004422{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004423 return cachedCollection(DocScripts);
andersca1d0b3772006-05-24 19:26:09 +00004424}
4425
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004426PassRefPtr<HTMLCollection> Document::links()
darinb9481ed2006-03-20 02:57:59 +00004427{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004428 return cachedCollection(DocLinks);
darinb9481ed2006-03-20 02:57:59 +00004429}
4430
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004431PassRefPtr<HTMLCollection> Document::forms()
darinb9481ed2006-03-20 02:57:59 +00004432{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004433 return cachedCollection(DocForms);
darinb9481ed2006-03-20 02:57:59 +00004434}
4435
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004436PassRefPtr<HTMLCollection> Document::anchors()
darinb9481ed2006-03-20 02:57:59 +00004437{
kling@webkit.org3e527e92011-12-16 23:11:11 +00004438 return cachedCollection(DocAnchors);
darinb9481ed2006-03-20 02:57:59 +00004439}
4440
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004441PassRefPtr<HTMLCollection> Document::all()
darinb9481ed2006-03-20 02:57:59 +00004442{
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004443 return cachedCollection(DocAll);
darinb9481ed2006-03-20 02:57:59 +00004444}
4445
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004446PassRefPtr<HTMLCollection> Document::windowNamedItems(const AtomicString& name)
darinb9481ed2006-03-20 02:57:59 +00004447{
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004448 NamedCollectionMap::AddResult result = m_windowNamedItemCollections.add(name, 0);
4449 if (!result.isNewEntry)
commit-queue@webkit.orgfa6afbc2012-08-28 20:54:45 +00004450 return result.iterator->second;
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004451
4452 RefPtr<HTMLNameCollection> collection = HTMLNameCollection::create(this, WindowNamedItems, name);
commit-queue@webkit.orgfa6afbc2012-08-28 20:54:45 +00004453 result.iterator->second = collection.get();
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004454 return collection.release();
darinb9481ed2006-03-20 02:57:59 +00004455}
4456
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004457PassRefPtr<HTMLCollection> Document::documentNamedItems(const AtomicString& name)
darinb9481ed2006-03-20 02:57:59 +00004458{
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004459 NamedCollectionMap::AddResult result = m_documentNamedItemCollections.add(name, 0);
4460 if (!result.isNewEntry)
commit-queue@webkit.orgfa6afbc2012-08-28 20:54:45 +00004461 return result.iterator->second;
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004462
4463 RefPtr<HTMLNameCollection> collection = HTMLNameCollection::create(this, DocumentNamedItems, name);
commit-queue@webkit.orgfa6afbc2012-08-28 20:54:45 +00004464 result.iterator->second = collection.get();
rniwa@webkit.org4823cc12012-07-09 17:40:09 +00004465 return collection.release();
4466}
4467
4468// FIXME: This caching mechanism should be merged that of DynamicNodeList in NodeRareData.
4469void Document::removeWindowNamedItemCache(HTMLCollection* collection, const AtomicString& name)
4470{
4471 ASSERT_UNUSED(collection, m_windowNamedItemCollections.get(name) == collection);
4472 m_windowNamedItemCollections.remove(name);
4473}
4474
4475void Document::removeDocumentNamedItemCache(HTMLCollection* collection, const AtomicString& name)
4476{
4477 ASSERT_UNUSED(collection, m_documentNamedItemCollections.get(name) == collection);
4478 m_documentNamedItemCollections.remove(name);
darinb9481ed2006-03-20 02:57:59 +00004479}
4480
darinb9481ed2006-03-20 02:57:59 +00004481void Document::finishedParsing()
4482{
tonyg@chromium.orgd299d8a72010-09-06 18:32:48 +00004483 ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
4484 ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
darinb9481ed2006-03-20 02:57:59 +00004485 setParsing(false);
tonyg@chromium.org64d18d92010-12-18 09:23:56 +00004486 if (!m_documentTiming.domContentLoadedEventStart)
simonjam@chromium.orgdfab5cf2011-12-15 18:45:29 +00004487 m_documentTiming.domContentLoadedEventStart = monotonicallyIncreasingTime();
ggaren@apple.com521f64b2009-09-24 05:53:23 +00004488 dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false));
tonyg@chromium.org64d18d92010-12-18 09:23:56 +00004489 if (!m_documentTiming.domContentLoadedEventEnd)
simonjam@chromium.orgdfab5cf2011-12-15 18:45:29 +00004490 m_documentTiming.domContentLoadedEventEnd = monotonicallyIncreasingTime();
jamesr@google.comee0be312010-04-06 03:08:45 +00004491
inferno@chromium.orga2e1c252011-06-16 21:27:30 +00004492 if (RefPtr<Frame> f = frame()) {
jamesr@google.comee0be312010-04-06 03:08:45 +00004493 // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
4494 // resource loads are complete. HTMLObjectElements can start loading their resources from
4495 // post attach callbacks triggered by recalcStyle(). This means if we parse out an <object>
4496 // tag and then reach the end of the document without updating styles, we might not have yet
4497 // started the resource load and might fire the window load event too early. To avoid this
4498 // we force the styles to be up to date before calling FrameLoader::finishedParsing().
4499 // See https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
4500 updateStyleIfNeeded();
4501
darinc370e7e2006-11-08 05:52:27 +00004502 f->loader()->finishedParsing();
bweinstein@apple.com1c773e22009-10-02 20:01:46 +00004503
vsevik@chromium.org29510e22011-09-23 10:46:54 +00004504 InspectorInstrumentation::domContentLoadedEventFired(f.get());
eric@webkit.orgf3d94222009-10-11 22:34:05 +00004505 }
kling@webkit.org7c575782012-09-04 02:19:26 +00004506
4507 // The ElementAttributeData sharing cache is only used during parsing since
4508 // that's when the majority of immutable attribute data will be created.
4509 m_immutableAttributeDataCache.clear();
darinb9481ed2006-03-20 02:57:59 +00004510}
4511
andersca75fd42c2006-05-08 21:27:25 +00004512PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
4513 XPathNSResolver* resolver,
4514 ExceptionCode& ec)
4515{
4516 if (!m_xpathEvaluator)
andersca@apple.comc442c152008-02-20 01:55:42 +00004517 m_xpathEvaluator = XPathEvaluator::create();
andersca75fd42c2006-05-08 21:27:25 +00004518 return m_xpathEvaluator->createExpression(expression, resolver, ec);
4519}
4520
darin7ab31092006-05-10 04:59:57 +00004521PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
andersca75fd42c2006-05-08 21:27:25 +00004522{
4523 if (!m_xpathEvaluator)
andersca@apple.comc442c152008-02-20 01:55:42 +00004524 m_xpathEvaluator = XPathEvaluator::create();
andersca75fd42c2006-05-08 21:27:25 +00004525 return m_xpathEvaluator->createNSResolver(nodeResolver);
4526}
4527
4528PassRefPtr<XPathResult> Document::evaluate(const String& expression,
4529 Node* contextNode,
4530 XPathNSResolver* resolver,
4531 unsigned short type,
4532 XPathResult* result,
4533 ExceptionCode& ec)
4534{
4535 if (!m_xpathEvaluator)
andersca@apple.comc442c152008-02-20 01:55:42 +00004536 m_xpathEvaluator = XPathEvaluator::create();
andersca75fd42c2006-05-08 21:27:25 +00004537 return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec);
4538}
4539
commit-queue@webkit.org466dbd42012-07-17 04:37:29 +00004540const Vector<IconURL>& Document::iconURLs()
beidsonb4e0ceb2006-09-19 02:21:52 +00004541{
commit-queue@webkit.org466dbd42012-07-17 04:37:29 +00004542 m_iconURLs.clear();
4543
4544 if (!head() || !(head()->children()))
4545 return m_iconURLs;
4546
4547 // Include any icons where type = link, rel = "shortcut icon".
4548 RefPtr<HTMLCollection> children = head()->children();
4549 unsigned int length = children->length();
4550 for (unsigned int i = 0; i < length; ++i) {
4551 Node* child = children->item(i);
4552 if (!child->hasTagName(linkTag))
4553 continue;
4554 HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(child);
4555 if (linkElement->iconType() != Favicon)
4556 continue;
4557 if (linkElement->href().isEmpty())
4558 continue;
4559
4560 // Put it at the front to ensure that icons seen later take precedence as required by the spec.
4561 IconURL newURL(linkElement->href(), linkElement->iconSizes(), linkElement->type(), linkElement->iconType());
4562 m_iconURLs.prepend(newURL);
4563 }
4564
commit-queue@webkit.org343b8a62011-09-21 01:49:03 +00004565 return m_iconURLs;
commit-queue@webkit.orge46967d2011-05-04 21:02:54 +00004566}
4567
commit-queue@webkit.org343b8a62011-09-21 01:49:03 +00004568void Document::addIconURL(const String& url, const String& mimeType, const String& sizes, IconType iconType)
commit-queue@webkit.orge46967d2011-05-04 21:02:54 +00004569{
commit-queue@webkit.org343b8a62011-09-21 01:49:03 +00004570 if (url.isEmpty())
4571 return;
4572
commit-queue@webkit.orge46967d2011-05-04 21:02:54 +00004573 // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "mimeType"
commit-queue@webkit.org343b8a62011-09-21 01:49:03 +00004574 IconURL newURL(KURL(ParsedURLString, url), sizes, mimeType, iconType);
commit-queue@webkit.orge46967d2011-05-04 21:02:54 +00004575
commit-queue@webkit.org343b8a62011-09-21 01:49:03 +00004576 if (Frame* f = frame()) {
4577 IconURL iconURL = f->loader()->icon()->iconURL(iconType);
4578 if (iconURL == newURL)
4579 f->loader()->didChangeIcons(iconType);
4580 }
beidsonb4e0ceb2006-09-19 02:21:52 +00004581}
4582
beidsonc030e972007-05-12 21:22:08 +00004583void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
4584{
4585 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
4586 return;
commit-queue@webkit.org466dbd42012-07-17 04:37:29 +00004587
beidsonc030e972007-05-12 21:22:08 +00004588 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
eric@webkit.org04253292010-03-08 19:22:44 +00004589 m_frame->selection()->updateSecureKeyboardEntryIfActive();
beidsonc030e972007-05-12 21:22:08 +00004590}
4591
4592bool Document::useSecureKeyboardEntryWhenActive() const
4593{
4594 return m_useSecureKeyboardEntryWhenActive;
4595}
4596
eric@webkit.org591bb232012-05-02 01:09:53 +00004597static bool isEligibleForSeamless(Document* parent, Document* child)
4598{
4599 // It should not matter what we return for the top-most document.
4600 if (!parent)
4601 return false;
4602 if (parent->isSandboxed(SandboxSeamlessIframes))
4603 return false;
4604 if (child->isSrcdocDocument())
4605 return true;
4606 if (parent->securityOrigin()->canAccess(child->securityOrigin()))
4607 return true;
4608 return parent->securityOrigin()->canRequest(child->url());
4609}
4610
abarth@webkit.org51aed8c2008-06-12 06:41:36 +00004611void Document::initSecurityContext()
weinig343b6ff2007-08-07 03:08:53 +00004612{
abarth@webkit.orgcd948f12011-11-14 10:26:49 +00004613 if (haveInitializedSecurityOrigin()) {
4614 ASSERT(securityOrigin());
4615 return;
4616 }
weinig@apple.com6b00e242008-01-08 01:30:27 +00004617
abarth@webkit.org51aed8c2008-06-12 06:41:36 +00004618 if (!m_frame) {
4619 // No source for a security context.
4620 // This can occur via document.implementation.createDocument().
benjamin@webkit.org512c7f52011-12-06 01:51:27 +00004621 m_cookieURL = KURL(ParsedURLString, emptyString());
abarth@webkit.org51ad70c2011-11-18 00:20:41 +00004622 setSecurityOrigin(SecurityOrigin::createUnique());
4623 setContentSecurityPolicy(ContentSecurityPolicy::create(this));
abarth@webkit.org51aed8c2008-06-12 06:41:36 +00004624 return;
4625 }
4626
4627 // In the common case, create the security context from the currently
abarth@webkit.orgd27ac262011-02-24 12:52:29 +00004628 // loading URL with a fresh content security policy.
japhet@chromium.org6a088ce2010-06-25 17:17:45 +00004629 m_cookieURL = m_url;
abarth@webkit.org51ad70c2011-11-18 00:20:41 +00004630 enforceSandboxFlags(m_frame->loader()->effectiveSandboxFlags());
abarth@webkit.org435c7592011-11-18 04:58:44 +00004631 setSecurityOrigin(isSandboxed(SandboxOrigin) ? SecurityOrigin::createUnique() : SecurityOrigin::create(m_url));
abarth@webkit.org51ad70c2011-11-18 00:20:41 +00004632 setContentSecurityPolicy(ContentSecurityPolicy::create(this));
abarth@webkit.org51aed8c2008-06-12 06:41:36 +00004633
abarth@webkit.orgeea90662011-11-09 07:58:49 +00004634 if (SecurityPolicy::allowSubstituteDataAccessToLocal()) {
abarth@webkit.orgaea97a02008-09-02 04:26:15 +00004635 // If this document was loaded with substituteData, then the document can
4636 // load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756
4637 // and https://bugs.webkit.org/show_bug.cgi?id=19760 for further
4638 // discussion.
beidson@apple.com197fbd32011-05-31 22:13:06 +00004639
4640 DocumentLoader* documentLoader = loader();
4641 if (documentLoader && documentLoader->substituteData().isValid())
ap@webkit.org0497fce2008-12-02 08:49:06 +00004642 securityOrigin()->grantLoadLocalResources();
abarth@webkit.orgaea97a02008-09-02 04:26:15 +00004643 }
abarth@webkit.org82988b52008-06-24 03:00:21 +00004644
abarth@webkit.org083c72e2009-02-27 20:52:55 +00004645 if (Settings* settings = this->settings()) {
4646 if (!settings->isWebSecurityEnabled()) {
ap@apple.comd8f6ae02012-05-24 18:42:58 +00004647 // Web security is turned off. We should let this document access every other document. This is used primary by testing
4648 // harnesses for web sites.
jonlee@apple.comd4ac1bd2012-03-21 00:34:59 +00004649 securityOrigin()->grantUniversalAccess();
ap@apple.comd8f6ae02012-05-24 18:42:58 +00004650 } else if (securityOrigin()->isLocal()) {
4651 if (settings->allowUniversalAccessFromFileURLs() || m_frame->loader()->client()->shouldForceUniversalAccessFromLocalURL(m_url)) {
4652 // Some clients want local URLs to have universal access, but that setting is dangerous for other clients.
4653 securityOrigin()->grantUniversalAccess();
4654 } else if (!settings->allowFileAccessFromFileURLs()) {
4655 // Some clients want local URLs to have even tighter restrictions by default, and not be able to access other local files.
4656 // FIXME 81578: The naming of this is confusing. Files with restricted access to other local files
4657 // still can have other privileges that can be remembered, thereby not making them unique origins.
4658 securityOrigin()->enforceFilePathSeparation();
4659 }
abarth@webkit.org083c72e2009-02-27 20:52:55 +00004660 }
jpfau@apple.comd5a0fa02012-09-08 02:05:36 +00004661 securityOrigin()->setStorageBlockingPolicy(settings->storageBlockingPolicy());
abarth@webkit.orgaf477982009-01-31 08:42:29 +00004662 }
4663
eric@webkit.org591bb232012-05-02 01:09:53 +00004664 Document* parentDocument = ownerElement() ? ownerElement()->document() : 0;
4665 if (parentDocument && m_frame->loader()->shouldTreatURLAsSrcdocDocument(url())) {
4666 m_isSrcdocDocument = true;
4667 setBaseURLOverride(parentDocument->baseURL());
4668 }
4669
4670 // FIXME: What happens if we inherit the security origin? This check may need to be later.
4671 // <iframe seamless src="about:blank"> likely won't work as-is.
4672 m_mayDisplaySeamlessWithParent = isEligibleForSeamless(parentDocument, this);
4673
abarth@webkit.orgd8cd61a2011-11-14 19:33:02 +00004674 if (!shouldInheritSecurityOriginFromOwner(m_url))
abarth@webkit.org51aed8c2008-06-12 06:41:36 +00004675 return;
4676
4677 // If we do not obtain a meaningful origin from the URL, then we try to
4678 // find one via the frame hierarchy.
4679
4680 Frame* ownerFrame = m_frame->tree()->parent();
4681 if (!ownerFrame)
4682 ownerFrame = m_frame->loader()->opener();
4683
abarth@webkit.orgcd948f12011-11-14 10:26:49 +00004684 if (!ownerFrame) {
4685 didFailToInitializeSecurityOrigin();
abarth@webkit.orge313e7b2011-11-14 07:57:10 +00004686 return;
abarth@webkit.orgcd948f12011-11-14 10:26:49 +00004687 }
abarth@webkit.orge313e7b2011-11-14 07:57:10 +00004688
abarth@webkit.orgb2515fa2012-04-04 05:54:26 +00004689 if (isSandboxed(SandboxOrigin)) {
4690 // If we're supposed to inherit our security origin from our owner,
4691 // but we're also sandboxed, the only thing we inherit is the ability
4692 // to load local resources. This lets about:blank iframes in file://
4693 // URL documents load images and other resources from the file system.
4694 if (ownerFrame->document()->securityOrigin()->canLoadLocalResources())
4695 securityOrigin()->grantLoadLocalResources();
4696 return;
4697 }
4698
abarth@webkit.orge313e7b2011-11-14 07:57:10 +00004699 m_cookieURL = ownerFrame->document()->cookieURL();
4700 // We alias the SecurityOrigins to match Firefox, see Bug 15313
4701 // https://bugs.webkit.org/show_bug.cgi?id=15313
abarth@webkit.org51ad70c2011-11-18 00:20:41 +00004702 setSecurityOrigin(ownerFrame->document()->securityOrigin());
abarth@webkit.org60383322012-05-04 03:45:06 +00004703}
4704
4705void Document::initContentSecurityPolicy()
4706{
commit-queue@webkit.org46fa2152012-08-01 21:34:13 +00004707 if (!m_frame->tree()->parent() || (!shouldInheritSecurityOriginFromOwner(m_url) && !isPluginDocument()))
abarth@webkit.org60383322012-05-04 03:45:06 +00004708 return;
commit-queue@webkit.org46fa2152012-08-01 21:34:13 +00004709
abarth@webkit.org60383322012-05-04 03:45:06 +00004710 contentSecurityPolicy()->copyStateFrom(m_frame->tree()->parent()->document()->contentSecurityPolicy());
darinb9481ed2006-03-20 02:57:59 +00004711}
weinig343b6ff2007-08-07 03:08:53 +00004712
abarth@webkit.org23d614a2012-06-01 09:26:27 +00004713void Document::didUpdateSecurityOrigin()
weinig@apple.com8fb8fd22008-01-30 21:56:26 +00004714{
abarth@webkit.org23d614a2012-06-01 09:26:27 +00004715 if (!m_frame)
4716 return;
abarth@webkit.org23d614a2012-06-01 09:26:27 +00004717 m_frame->script()->updateSecurityOrigin();
weinig@apple.com8fb8fd22008-01-30 21:56:26 +00004718}
4719
eric@webkit.orga1d89652010-01-21 03:49:51 +00004720bool Document::isContextThread() const
4721{
4722 return isMainThread();
4723}
4724
beidson@apple.com08c61752009-12-03 19:04:40 +00004725void Document::updateURLForPushOrReplaceState(const KURL& url)
4726{
4727 Frame* f = frame();
4728 if (!f)
4729 return;
4730
4731 setURL(url);
japhet@chromium.orgb254c9b2011-01-26 19:14:26 +00004732 f->loader()->setOutgoingReferrer(url);
beidson@apple.com197fbd32011-05-31 22:13:06 +00004733
4734 if (DocumentLoader* documentLoader = loader())
4735 documentLoader->replaceRequestURLForSameDocumentNavigation(url);
beidson@apple.com08c61752009-12-03 19:04:40 +00004736}
4737
jsbell@chromium.org2ba79912012-05-17 01:36:11 +00004738void Document::statePopped(PassRefPtr<SerializedScriptValue> stateObject)
beidson@apple.com08c61752009-12-03 19:04:40 +00004739{
mihaip@chromium.orgd8016512010-10-09 00:01:57 +00004740 if (!frame())
beidson@apple.com08c61752009-12-03 19:04:40 +00004741 return;
4742
mihaip@chromium.orgd8016512010-10-09 00:01:57 +00004743 // Per step 11 of section 6.5.9 (history traversal) of the HTML5 spec, we
4744 // defer firing of popstate until we're in the complete state.
4745 if (m_readyState == Complete)
beidson@apple.com43a414c2010-03-19 18:25:21 +00004746 enqueuePopstateEvent(stateObject);
beidson@apple.com08c61752009-12-03 19:04:40 +00004747 else
4748 m_pendingStateObject = stateObject;
4749}
4750
simon.fraser@apple.com9998eac2010-02-05 19:50:24 +00004751void Document::updateFocusAppearanceSoon(bool restorePreviousSelection)
darin438e6272007-08-16 16:29:48 +00004752{
simon.fraser@apple.com9998eac2010-02-05 19:50:24 +00004753 m_updateFocusAppearanceRestoresSelection = restorePreviousSelection;
darin438e6272007-08-16 16:29:48 +00004754 if (!m_updateFocusAppearanceTimer.isActive())
4755 m_updateFocusAppearanceTimer.startOneShot(0);
4756}
4757
4758void Document::cancelFocusAppearanceUpdate()
4759{
4760 m_updateFocusAppearanceTimer.stop();
4761}
4762
4763void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
4764{
4765 Node* node = focusedNode();
4766 if (!node)
4767 return;
4768 if (!node->isElementNode())
4769 return;
4770
4771 updateLayout();
4772
4773 Element* element = static_cast<Element*>(node);
4774 if (element->isFocusable())
simon.fraser@apple.com9998eac2010-02-05 19:50:24 +00004775 element->updateFocusAppearance(m_updateFocusAppearanceRestoresSelection);
darin438e6272007-08-16 16:29:48 +00004776}
4777
darin@apple.comf28fa1b2008-03-15 17:26:28 +00004778void Document::attachRange(Range* range)
4779{
4780 ASSERT(!m_ranges.contains(range));
4781 m_ranges.add(range);
4782}
4783
4784void Document::detachRange(Range* range)
4785{
eric@webkit.org11875df2009-06-11 21:20:01 +00004786 // We don't ASSERT m_ranges.contains(range) to allow us to call this
4787 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044
darin@apple.comf28fa1b2008-03-15 17:26:28 +00004788 m_ranges.remove(range);
4789}
4790
cmarrin@apple.comf493aa22009-08-25 18:45:56 +00004791CanvasRenderingContext* Document::getCSSCanvasContext(const String& type, const String& name, int width, int height)
hyatt@apple.com68382152008-04-17 04:13:36 +00004792{
darin@apple.coma132a512011-12-25 19:03:16 +00004793 HTMLCanvasElement* element = getCSSCanvasElement(name);
4794 if (!element)
hyatt@apple.com68382152008-04-17 04:13:36 +00004795 return 0;
darin@apple.coma132a512011-12-25 19:03:16 +00004796 element->setSize(IntSize(width, height));
4797 return element->getContext(type);
hyatt@apple.com68382152008-04-17 04:13:36 +00004798}
4799
4800HTMLCanvasElement* Document::getCSSCanvasElement(const String& name)
4801{
commit-queue@webkit.orgfa6afbc2012-08-28 20:54:45 +00004802 RefPtr<HTMLCanvasElement>& element = m_cssCanvasElements.add(name, 0).iterator->second;
darin@apple.coma132a512011-12-25 19:03:16 +00004803 if (!element)
4804 element = HTMLCanvasElement::create(this);
4805 return element.get();
hyatt@apple.com68382152008-04-17 04:13:36 +00004806}
4807
collinj@webkit.org9c672f62008-09-19 04:15:14 +00004808void Document::initDNSPrefetch()
4809{
timothy@apple.com217852f2010-07-01 19:32:15 +00004810 Settings* settings = this->settings();
4811
collinj@webkit.org9c672f62008-09-19 04:15:14 +00004812 m_haveExplicitlyDisabledDNSPrefetch = false;
timothy@apple.com217852f2010-07-01 19:32:15 +00004813 m_isDNSPrefetchEnabled = settings && settings->dnsPrefetchingEnabled() && securityOrigin()->protocol() == "http";
collinj@webkit.org9c672f62008-09-19 04:15:14 +00004814
4815 // Inherit DNS prefetch opt-out from parent frame
4816 if (Document* parent = parentDocument()) {
4817 if (!parent->isDNSPrefetchEnabled())
4818 m_isDNSPrefetchEnabled = false;
4819 }
4820}
4821
4822void Document::parseDNSPrefetchControlHeader(const String& dnsPrefetchControl)
4823{
4824 if (equalIgnoringCase(dnsPrefetchControl, "on") && !m_haveExplicitlyDisabledDNSPrefetch) {
4825 m_isDNSPrefetchEnabled = true;
4826 return;
4827 }
4828
4829 m_isDNSPrefetchEnabled = false;
4830 m_haveExplicitlyDisabledDNSPrefetch = true;
4831}
4832
vsevik@chromium.org0c3bdd92012-01-12 10:56:52 +00004833void Document::addMessage(MessageSource source, MessageType type, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack)
eric@webkit.orgb571be32010-04-07 16:18:38 +00004834{
commit-queue@webkit.orge5a8ade2011-11-04 22:24:17 +00004835 if (!isContextThread()) {
4836 postTask(AddConsoleMessageTask::create(source, type, level, message));
4837 return;
4838 }
4839
ap@webkit.orge9b6b592008-11-19 17:42:39 +00004840 if (DOMWindow* window = domWindow())
vsevik@chromium.org0c3bdd92012-01-12 10:56:52 +00004841 window->console()->addMessage(source, type, level, message, sourceURL, lineNumber, callStack);
oliver@apple.com991c37e2009-03-10 09:44:30 +00004842}
4843
ossy@webkit.org95c1bc42011-01-20 16:30:54 +00004844struct PerformTaskContext {
4845 WTF_MAKE_NONCOPYABLE(PerformTaskContext); WTF_MAKE_FAST_ALLOCATED;
4846public:
dimich@chromium.org948b9a32010-01-15 21:47:15 +00004847 PerformTaskContext(PassRefPtr<DocumentWeakReference> documentReference, PassOwnPtr<ScriptExecutionContext::Task> task)
4848 : documentReference(documentReference)
dimich@chromium.org301cf2b2009-11-18 20:25:52 +00004849 , task(task)
4850 {
4851 }
4852
dimich@chromium.org948b9a32010-01-15 21:47:15 +00004853 RefPtr<DocumentWeakReference> documentReference;
dimich@chromium.org301cf2b2009-11-18 20:25:52 +00004854 OwnPtr<ScriptExecutionContext::Task> task;
4855};
4856
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004857void Document::didReceiveTask(void* untypedContext)
dimich@chromium.org301cf2b2009-11-18 20:25:52 +00004858{
dimich@chromium.org948b9a32010-01-15 21:47:15 +00004859 ASSERT(isMainThread());
4860
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004861 OwnPtr<PerformTaskContext> context = adoptPtr(static_cast<PerformTaskContext*>(untypedContext));
dimich@chromium.org948b9a32010-01-15 21:47:15 +00004862 ASSERT(context);
4863
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004864 Document* document = context->documentReference->document();
4865 if (!document)
4866 return;
dimich@chromium.org948b9a32010-01-15 21:47:15 +00004867
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004868 Page* page = document->page();
4869 if ((page && page->defersLoading()) || !document->m_pendingTasks.isEmpty()) {
4870 document->m_pendingTasks.append(context->task.release());
4871 return;
4872 }
4873
4874 context->task->performTask(document);
dimich@chromium.org301cf2b2009-11-18 20:25:52 +00004875}
4876
dimich@chromium.org142155a2009-11-02 21:31:22 +00004877void Document::postTask(PassOwnPtr<Task> task)
ap@webkit.orga3f2d9f2008-12-04 07:20:45 +00004878{
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004879 callOnMainThread(didReceiveTask, new PerformTaskContext(m_weakReference, task));
4880}
4881
4882void Document::pendingTasksTimerFired(Timer<Document>*)
4883{
4884 while (!m_pendingTasks.isEmpty()) {
4885 OwnPtr<Task> task = m_pendingTasks[0].release();
4886 m_pendingTasks.remove(0);
4887 task->performTask(this);
4888 }
4889}
4890
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004891void Document::suspendScheduledTasks(ActiveDOMObject::ReasonForSuspension reason)
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004892{
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004893 ASSERT(!m_scheduledTasksAreSuspended);
4894
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004895 suspendScriptedAnimationControllerCallbacks();
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004896 suspendActiveDOMObjects(reason);
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004897 scriptRunner()->suspend();
4898 m_pendingTasksTimer.stop();
4899 if (m_parser)
4900 m_parser->suspendScheduledTasks();
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004901
4902 m_scheduledTasksAreSuspended = true;
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004903}
4904
4905void Document::resumeScheduledTasks()
4906{
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004907 ASSERT(m_scheduledTasksAreSuspended);
4908
commit-queue@webkit.org160529f2011-12-07 23:41:21 +00004909 if (m_parser)
4910 m_parser->resumeScheduledTasks();
4911 if (!m_pendingTasks.isEmpty())
4912 m_pendingTasksTimer.startOneShot(0);
4913 scriptRunner()->resume();
4914 resumeActiveDOMObjects();
4915 resumeScriptedAnimationControllerCallbacks();
beidson@apple.comb1bc1b72012-04-20 21:29:00 +00004916
4917 m_scheduledTasksAreSuspended = false;
ap@webkit.orga3f2d9f2008-12-04 07:20:45 +00004918}
4919
jamesr@google.com9f8b52b2011-02-16 00:53:36 +00004920void Document::suspendScriptedAnimationControllerCallbacks()
4921{
4922#if ENABLE(REQUEST_ANIMATION_FRAME)
4923 if (m_scriptedAnimationController)
4924 m_scriptedAnimationController->suspend();
4925#endif
4926}
4927
4928void Document::resumeScriptedAnimationControllerCallbacks()
4929{
4930#if ENABLE(REQUEST_ANIMATION_FRAME)
4931 if (m_scriptedAnimationController)
4932 m_scriptedAnimationController->resume();
4933#endif
4934}
4935
cmarrin@apple.com4386e022011-10-13 21:59:25 +00004936void Document::windowScreenDidChange(PlatformDisplayID displayID)
4937{
4938#if ENABLE(REQUEST_ANIMATION_FRAME)
4939 if (m_scriptedAnimationController)
4940 m_scriptedAnimationController->windowScreenDidChange(displayID);
commit-queue@webkit.org11b6e672012-01-16 11:09:00 +00004941#else
4942 UNUSED_PARAM(displayID);
cmarrin@apple.com4386e022011-10-13 21:59:25 +00004943#endif
4944}
4945
4946
ap@webkit.org78030882009-02-28 08:06:32 +00004947String Document::displayStringModifiedByEncoding(const String& str) const
4948{
4949 if (m_decoder)
4950 return m_decoder->encoding().displayString(str.impl());
4951 return str;
4952}
4953
4954PassRefPtr<StringImpl> Document::displayStringModifiedByEncoding(PassRefPtr<StringImpl> str) const
4955{
4956 if (m_decoder)
4957 return m_decoder->encoding().displayString(str);
4958 return str;
4959}
4960
4961void Document::displayBufferModifiedByEncoding(UChar* buffer, unsigned len) const
4962{
4963 if (m_decoder)
4964 m_decoder->encoding().displayBuffer(buffer, len);
4965}
4966
beidson@apple.com43a414c2010-03-19 18:25:21 +00004967void Document::enqueuePageshowEvent(PageshowEventPersistence persisted)
4968{
4969 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36334 Pageshow event needs to fire asynchronously.
4970 dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, persisted), this);
4971}
4972
mihaip@chromium.org6b40a772010-09-21 00:22:13 +00004973void Document::enqueueHashchangeEvent(const String& oldURL, const String& newURL)
beidson@apple.com43a414c2010-03-19 18:25:21 +00004974{
mihaip@chromium.orgb042a702010-12-14 22:52:24 +00004975 enqueueWindowEvent(HashChangeEvent::create(oldURL, newURL));
beidson@apple.com43a414c2010-03-19 18:25:21 +00004976}
4977
4978void Document::enqueuePopstateEvent(PassRefPtr<SerializedScriptValue> stateObject)
4979{
4980 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=36202 Popstate event needs to fire asynchronously
commit-queue@webkit.org7a2b40f2012-02-23 03:05:55 +00004981 dispatchWindowEvent(PopStateEvent::create(stateObject, domWindow() ? domWindow()->history() : 0));
beidson@apple.com43a414c2010-03-19 18:25:21 +00004982}
4983
darin@apple.comcfc5f062010-05-12 00:35:38 +00004984void Document::addMediaCanStartListener(MediaCanStartListener* listener)
4985{
bdakin@apple.combc39dc82010-05-12 16:52:45 +00004986 ASSERT(!m_mediaCanStartListeners.contains(listener));
4987 m_mediaCanStartListeners.add(listener);
darin@apple.comcfc5f062010-05-12 00:35:38 +00004988}
4989
4990void Document::removeMediaCanStartListener(MediaCanStartListener* listener)
4991{
bdakin@apple.combc39dc82010-05-12 16:52:45 +00004992 ASSERT(m_mediaCanStartListeners.contains(listener));
4993 m_mediaCanStartListeners.remove(listener);
4994}
4995
4996MediaCanStartListener* Document::takeAnyMediaCanStartListener()
4997{
4998 HashSet<MediaCanStartListener*>::iterator slot = m_mediaCanStartListeners.begin();
4999 if (slot == m_mediaCanStartListeners.end())
5000 return 0;
5001 MediaCanStartListener* listener = *slot;
5002 m_mediaCanStartListeners.remove(slot);
5003 return listener;
darin@apple.comcfc5f062010-05-12 00:35:38 +00005004}
5005
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005006#if ENABLE(FULLSCREEN_API)
jer.noble@apple.com67f9c902011-03-14 17:52:31 +00005007bool Document::fullScreenIsAllowedForElement(Element* element) const
5008{
5009 ASSERT(element);
scheib@chromium.orge0e60032012-07-18 20:06:12 +00005010 return isAttributeOnAllOwners(webkitallowfullscreenAttr, element->document()->ownerElement());
jer.noble@apple.com67f9c902011-03-14 17:52:31 +00005011}
5012
jer.noble@apple.com009a1cb2011-05-25 21:38:31 +00005013void Document::requestFullScreenForElement(Element* element, unsigned short flags, FullScreenCheckType checkType)
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005014{
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005015 // The Mozilla Full Screen API <https://wiki.mozilla.org/Gecko:FullScreenAPI> has different requirements
5016 // for full screen mode, and do not have the concept of a full screen element stack.
5017 bool inLegacyMozillaMode = (flags & Element::LEGACY_MOZILLA_REQUEST);
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005018
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005019 do {
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005020 if (!element)
5021 element = documentElement();
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005022
5023 // 1. If any of the following conditions are true, terminate these steps and queue a task to fire
5024 // an event named fullscreenerror with its bubbles attribute set to true on the context object's
5025 // node document:
5026
5027 // The context object is not in a document.
5028 if (!element->inDocument())
5029 break;
5030
5031 // The context object's node document, or an ancestor browsing context's document does not have
5032 // the fullscreen enabled flag set.
scheib@chromium.org23765bb2012-07-17 00:52:57 +00005033 if (checkType == EnforceIFrameAllowFullScreenRequirement && !fullScreenIsAllowedForElement(element))
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005034 break;
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005035
5036 // The context object's node document fullscreen element stack is not empty and its top element
5037 // is not an ancestor of the context object. (NOTE: Ignore this requirement if the request was
5038 // made via the legacy Mozilla-style API.)
5039 if (!m_fullScreenElementStack.isEmpty() && !m_fullScreenElementStack.first()->contains(element) && !inLegacyMozillaMode)
5040 break;
5041
5042 // A descendant browsing context's document has a non-empty fullscreen element stack.
5043 bool descendentHasNonEmptyStack = false;
5044 for (Frame* descendant = frame() ? frame()->tree()->traverseNext() : 0; descendant; descendant = descendant->tree()->traverseNext()) {
5045 if (descendant->document()->webkitFullscreenElement()) {
5046 descendentHasNonEmptyStack = true;
5047 break;
5048 }
5049 }
5050 if (descendentHasNonEmptyStack && !inLegacyMozillaMode)
5051 break;
5052
scheib@chromium.orgb779c1d2012-05-02 04:28:14 +00005053 // This algorithm is not allowed to show a pop-up:
5054 // An algorithm is allowed to show a pop-up if, in the task in which the algorithm is running, either:
5055 // - an activation behavior is currently being processed whose click event was trusted, or
5056 // - the event listener for a trusted click event is being handled.
5057 if (!ScriptController::processingUserGesture())
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005058 break;
5059
5060 // There is a previously-established user preference, security risk, or platform limitation.
5061 if (!page() || !page()->settings()->fullScreenEnabled())
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005062 break;
5063
5064 if (!page()->chrome()->client()->supportsFullScreenForElement(element, flags & Element::ALLOW_KEYBOARD_INPUT))
5065 break;
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005066
5067 // 2. Let doc be element's node document. (i.e. "this")
5068 Document* currentDoc = this;
5069
5070 // 3. Let docs be all doc's ancestor browsing context's documents (if any) and doc.
5071 Deque<Document*> docs;
5072
5073 do {
5074 docs.prepend(currentDoc);
5075 currentDoc = currentDoc->ownerElement() ? currentDoc->ownerElement()->document() : 0;
5076 } while (currentDoc);
5077
5078 // 4. For each document in docs, run these substeps:
5079 Deque<Document*>::iterator current = docs.begin(), following = docs.begin();
5080
5081 do {
5082 ++following;
5083
5084 // 1. Let following document be the document after document in docs, or null if there is no
5085 // such document.
5086 Document* currentDoc = *current;
5087 Document* followingDoc = following != docs.end() ? *following : 0;
5088
5089 // 2. If following document is null, push context object on document's fullscreen element
5090 // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
5091 // set to true on the document.
5092 if (!followingDoc) {
5093 currentDoc->pushFullscreenElementStack(element);
5094 addDocumentToFullScreenChangeEventQueue(currentDoc);
5095 continue;
5096 }
5097
5098 // 3. Otherwise, if document's fullscreen element stack is either empty or its top element
5099 // is not following document's browsing context container,
5100 Element* topElement = currentDoc->webkitFullscreenElement();
5101 if (!topElement || topElement != followingDoc->ownerElement()) {
5102 // ...push following document's browsing context container on document's fullscreen element
5103 // stack, and queue a task to fire an event named fullscreenchange with its bubbles attribute
5104 // set to true on document.
5105 currentDoc->pushFullscreenElementStack(followingDoc->ownerElement());
5106 addDocumentToFullScreenChangeEventQueue(currentDoc);
5107 continue;
5108 }
5109
5110 // 4. Otherwise, do nothing for this document. It stays the same.
5111 } while (++current != docs.end());
5112
5113 // 5. Return, and run the remaining steps asynchronously.
5114 // 6. Optionally, perform some animation.
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005115 m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
5116 page()->chrome()->client()->enterFullScreenForElement(element);
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005117
5118 // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
jer.noble@apple.com67f9c902011-03-14 17:52:31 +00005119 return;
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005120 } while (0);
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005121
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005122 m_fullScreenErrorEventTargetQueue.append(element ? element : documentElement());
5123 m_fullScreenChangeDelayTimer.startOneShot(0);
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005124}
5125
5126void Document::webkitCancelFullScreen()
5127{
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005128 // The Mozilla "cancelFullScreen()" API behaves like the W3C "fully exit fullscreen" behavior, which
5129 // is defined as:
5130 // "To fully exit fullscreen act as if the exitFullscreen() method was invoked on the top-level browsing
5131 // context's document and subsequently empty that document's fullscreen element stack."
5132 if (!topDocument()->webkitFullscreenElement())
5133 return;
5134
5135 // To achieve that aim, remove all the elements from the top document's stack except for the first before
5136 // calling webkitExitFullscreen():
5137 Deque<RefPtr<Element> > replacementFullscreenElementStack;
5138 replacementFullscreenElementStack.prepend(topDocument()->webkitFullscreenElement());
5139 topDocument()->m_fullScreenElementStack.swap(replacementFullscreenElementStack);
5140
5141 topDocument()->webkitExitFullscreen();
5142}
5143
5144void Document::webkitExitFullscreen()
5145{
5146 // The exitFullscreen() method must run these steps:
5147
5148 // 1. Let doc be the context object. (i.e. "this")
5149 Document* currentDoc = this;
5150
5151 // 2. If doc's fullscreen element stack is empty, terminate these steps.
5152 if (m_fullScreenElementStack.isEmpty())
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005153 return;
5154
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005155 // 3. Let descendants be all the doc's descendant browsing context's documents with a non-empty fullscreen
5156 // element stack (if any), ordered so that the child of the doc is last and the document furthest
5157 // away from the doc is first.
5158 Deque<RefPtr<Document> > descendants;
5159 for (Frame* descendant = frame() ? frame()->tree()->traverseNext() : 0; descendant; descendant = descendant->tree()->traverseNext()) {
5160 if (descendant->document()->webkitFullscreenElement())
5161 descendants.prepend(descendant->document());
5162 }
5163
5164 // 4. For each descendant in descendants, empty descendant's fullscreen element stack, and queue a
5165 // task to fire an event named fullscreenchange with its bubbles attribute set to true on descendant.
5166 for (Deque<RefPtr<Document> >::iterator i = descendants.begin(); i != descendants.end(); ++i) {
5167 (*i)->clearFullscreenElementStack();
5168 addDocumentToFullScreenChangeEventQueue(i->get());
5169 }
5170
5171 // 5. While doc is not null, run these substeps:
5172 Element* newTop = 0;
5173 while (currentDoc) {
5174 // 1. Pop the top element of doc's fullscreen element stack.
5175 currentDoc->popFullscreenElementStack();
5176
5177 // If doc's fullscreen element stack is non-empty and the element now at the top is either
5178 // not in a document or its node document is not doc, repeat this substep.
5179 newTop = currentDoc->webkitFullscreenElement();
5180 if (newTop && (!newTop->inDocument() || newTop->document() != currentDoc))
5181 continue;
5182
5183 // 2. Queue a task to fire an event named fullscreenchange with its bubbles attribute set to true
5184 // on doc.
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005185 addDocumentToFullScreenChangeEventQueue(currentDoc);
5186
5187 // 3. If doc's fullscreen element stack is empty and doc's browsing context has a browsing context
5188 // container, set doc to that browsing context container's node document.
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00005189 if (!newTop && currentDoc->ownerElement()) {
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005190 currentDoc = currentDoc->ownerElement()->document();
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00005191 continue;
5192 }
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005193
5194 // 4. Otherwise, set doc to null.
5195 currentDoc = 0;
5196 }
5197
5198 // 6. Return, and run the remaining steps asynchronously.
5199 // 7. Optionally, perform some animation.
5200
5201 // Only exit out of full screen window mode if there are no remaining elements in the
5202 // full screen stack.
5203 if (!newTop) {
5204 page()->chrome()->client()->exitFullScreenForElement(m_fullScreenElement.get());
5205 return;
5206 }
5207
5208 // Otherwise, notify the chrome of the new full screen element.
5209 page()->chrome()->client()->enterFullScreenForElement(newTop);
5210}
5211
5212bool Document::webkitFullscreenEnabled() const
5213{
5214 // 4. The fullscreenEnabled attribute must return true if the context object and all ancestor
5215 // browsing context's documents have their fullscreen enabled flag set, or false otherwise.
5216
5217 // Top-level browsing contexts are implied to have their allowFullScreen attribute set.
scheib@chromium.orge0e60032012-07-18 20:06:12 +00005218 return isAttributeOnAllOwners(webkitallowfullscreenAttr, ownerElement());
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005219}
jer.noble@apple.come8864852011-04-22 23:52:44 +00005220
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005221void Document::webkitWillEnterFullScreenForElement(Element* element)
5222{
jer.noble@apple.com40284f32012-04-04 21:11:14 +00005223 if (!attached() || inPageCache())
5224 return;
5225
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005226 ASSERT(element);
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005227
5228 // Protect against being called after the document has been removed from the page.
5229 if (!page())
5230 return;
5231
5232 ASSERT(page()->settings()->fullScreenEnabled());
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005233
koz@chromium.org24394b42011-09-17 06:07:42 +00005234 if (m_fullScreenRenderer)
5235 m_fullScreenRenderer->unwrapRenderer();
5236
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005237 m_fullScreenElement = element;
jer.noble@apple.com5346d012011-06-03 18:48:15 +00005238
commit-queue@webkit.org13bbf8c2012-05-02 00:39:31 +00005239#if USE(NATIVE_FULLSCREEN_VIDEO)
5240 if (element && element->isMediaElement())
5241 return;
5242#endif
5243
jer.noble@apple.com5346d012011-06-03 18:48:15 +00005244 // Create a placeholder block for a the full-screen element, to keep the page from reflowing
5245 // when the element is removed from the normal flow. Only do this for a RenderBox, as only
5246 // a box will have a frameRect. The placeholder will be created in setFullScreenRenderer()
5247 // during layout.
5248 RenderObject* renderer = m_fullScreenElement->renderer();
jer.noble@apple.com0c788412011-06-11 03:36:15 +00005249 bool shouldCreatePlaceholder = renderer && renderer->isBox();
jer.noble@apple.com5346d012011-06-03 18:48:15 +00005250 if (shouldCreatePlaceholder) {
5251 m_savedPlaceholderFrameRect = toRenderBox(renderer)->frameRect();
5252 m_savedPlaceholderRenderStyle = RenderStyle::clone(renderer->style());
5253 }
5254
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005255 if (m_fullScreenElement != documentElement())
inferno@chromium.orgad473f52012-08-02 20:44:31 +00005256 RenderFullScreen::wrapRenderer(renderer, renderer ? renderer->parent() : 0, this);
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005257
jer.noble@apple.com548e3362011-06-18 20:34:57 +00005258 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
jer.noble@apple.come8864852011-04-22 23:52:44 +00005259
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005260 recalcStyle(Force);
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005261}
commit-queue@webkit.org13bbf8c2012-05-02 00:39:31 +00005262
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005263void Document::webkitDidEnterFullScreenForElement(Element*)
5264{
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005265 if (!m_fullScreenElement)
5266 return;
jer.noble@apple.com40284f32012-04-04 21:11:14 +00005267
5268 if (!attached() || inPageCache())
5269 return;
5270
mitz@apple.com571ae7c2011-05-30 00:19:51 +00005271 m_fullScreenElement->didBecomeFullscreenElement();
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005272
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005273 m_fullScreenChangeDelayTimer.startOneShot(0);
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005274}
5275
5276void Document::webkitWillExitFullScreenForElement(Element*)
5277{
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005278 if (!m_fullScreenElement)
5279 return;
5280
jer.noble@apple.com40284f32012-04-04 21:11:14 +00005281 if (!attached() || inPageCache())
5282 return;
5283
mitz@apple.com571ae7c2011-05-30 00:19:51 +00005284 m_fullScreenElement->willStopBeingFullscreenElement();
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005285}
5286
jer.noble@apple.com08429c92011-01-07 23:09:25 +00005287void Document::webkitDidExitFullScreenForElement(Element*)
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005288{
jer.noble@apple.com53465aa2012-04-20 22:33:46 +00005289 if (!m_fullScreenElement)
5290 return;
5291
jer.noble@apple.com40284f32012-04-04 21:11:14 +00005292 if (!attached() || inPageCache())
5293 return;
5294
jer.noble@apple.com53465aa2012-04-20 22:33:46 +00005295 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
5296
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005297 m_areKeysEnabledInFullScreen = false;
koz@chromium.orgcceed2e2011-09-05 06:43:32 +00005298
koz@chromium.org24394b42011-09-17 06:07:42 +00005299 if (m_fullScreenRenderer)
5300 m_fullScreenRenderer->unwrapRenderer();
scherkus@chromium.org17b740a2011-04-18 19:27:35 +00005301
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005302 m_fullScreenElement = 0;
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005303 scheduleForcedStyleRecalc();
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005304
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00005305 // When webkitCancelFullScreen is called, we call webkitExitFullScreen on the topDocument(). That
5306 // means that the events will be queued there. So if we have no events here, start the timer on
5307 // the exiting document.
5308 Document* exitingDocument = this;
5309 if (m_fullScreenChangeEventTargetQueue.isEmpty() && m_fullScreenErrorEventTargetQueue.isEmpty())
5310 exitingDocument = topDocument();
5311 exitingDocument->m_fullScreenChangeDelayTimer.startOneShot(0);
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005312}
5313
5314void Document::setFullScreenRenderer(RenderFullScreen* renderer)
5315{
jer.noble@apple.com2596abb2011-03-16 23:48:44 +00005316 if (renderer == m_fullScreenRenderer)
5317 return;
5318
jer.noble@apple.com5346d012011-06-03 18:48:15 +00005319 if (renderer && m_savedPlaceholderRenderStyle)
5320 renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_savedPlaceholderFrameRect);
5321 else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeholder()) {
5322 RenderBlock* placeholder = m_fullScreenRenderer->placeholder();
5323 renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), placeholder->frameRect());
5324 }
5325
jer.noble@apple.com2596abb2011-03-16 23:48:44 +00005326 if (m_fullScreenRenderer)
5327 m_fullScreenRenderer->destroy();
jer.noble@apple.com961d45b2011-05-26 19:30:48 +00005328 ASSERT(!m_fullScreenRenderer);
5329
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005330 m_fullScreenRenderer = renderer;
5331
5332 // This notification can come in after the page has been destroyed.
5333 if (page())
5334 page()->chrome()->client()->fullScreenRendererChanged(m_fullScreenRenderer);
5335}
jer.noble@apple.com961d45b2011-05-26 19:30:48 +00005336
5337void Document::fullScreenRendererDestroyed()
5338{
5339 m_fullScreenRenderer = 0;
5340
5341 if (page())
5342 page()->chrome()->client()->fullScreenRendererChanged(0);
5343}
5344
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005345void Document::setFullScreenRendererSize(const IntSize& size)
5346{
5347 ASSERT(m_fullScreenRenderer);
5348 if (!m_fullScreenRenderer)
5349 return;
5350
5351 if (m_fullScreenRenderer) {
5352 RefPtr<RenderStyle> newStyle = RenderStyle::clone(m_fullScreenRenderer->style());
5353 newStyle->setWidth(Length(size.width(), WebCore::Fixed));
5354 newStyle->setHeight(Length(size.height(), WebCore::Fixed));
5355 newStyle->setTop(Length(0, WebCore::Fixed));
5356 newStyle->setLeft(Length(0, WebCore::Fixed));
5357 m_fullScreenRenderer->setStyle(newStyle);
jer.noble@apple.com65e744e2011-03-12 05:28:40 +00005358 updateLayout();
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005359 }
5360}
5361
5362void Document::setFullScreenRendererBackgroundColor(Color backgroundColor)
5363{
5364 if (!m_fullScreenRenderer)
5365 return;
5366
5367 RefPtr<RenderStyle> newStyle = RenderStyle::clone(m_fullScreenRenderer->style());
5368 newStyle->setBackgroundColor(backgroundColor);
5369 m_fullScreenRenderer->setStyle(newStyle);
5370}
5371
5372void Document::fullScreenChangeDelayTimerFired(Timer<Document>*)
5373{
commit-queue@webkit.org921569d2012-09-21 23:20:08 +00005374 // Since we dispatch events in this function, it's possible that the
5375 // document will be detached and GC'd. We protect it here to make sure we
5376 // can finish the function successfully.
5377 RefPtr<Document> protectDocument(this);
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005378 Deque<RefPtr<Node> > changeQueue;
5379 m_fullScreenChangeEventTargetQueue.swap(changeQueue);
5380
5381 while (!changeQueue.isEmpty()) {
5382 RefPtr<Node> node = changeQueue.takeFirst();
5383 if (!node)
5384 node = documentElement();
commit-queue@webkit.org921569d2012-09-21 23:20:08 +00005385 // The dispatchEvent below may have blown away our documentElement.
5386 if (!node)
5387 continue;
jer.noble@apple.com7a362df2011-05-18 06:12:12 +00005388
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00005389 // If the element was removed from our tree, also message the documentElement. Since we may
5390 // have a document hierarchy, check that node isn't in another document.
5391 if (!contains(node.get()) && !node->inDocument())
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005392 changeQueue.append(documentElement());
jer.noble@apple.comb6054d32011-05-21 22:30:01 +00005393
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005394 node->dispatchEvent(Event::create(eventNames().webkitfullscreenchangeEvent, true, false));
jer.noble@apple.com5a4d18e2011-05-14 17:29:14 +00005395 }
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005396
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005397 Deque<RefPtr<Node> > errorQueue;
5398 m_fullScreenErrorEventTargetQueue.swap(errorQueue);
5399
5400 while (!errorQueue.isEmpty()) {
5401 RefPtr<Node> node = errorQueue.takeFirst();
5402 if (!node)
5403 node = documentElement();
commit-queue@webkit.org921569d2012-09-21 23:20:08 +00005404 // The dispatchEvent below may have blown away our documentElement.
5405 if (!node)
5406 continue;
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005407
bbudge@chromium.org9b3a1282012-08-20 18:11:22 +00005408 // If the element was removed from our tree, also message the documentElement. Since we may
5409 // have a document hierarchy, check that node isn't in another document.
5410 if (!contains(node.get()) && !node->inDocument())
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005411 errorQueue.append(documentElement());
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005412
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005413 node->dispatchEvent(Event::create(eventNames().webkitfullscreenerrorEvent, true, false));
jer.noble@apple.comd20c4642012-01-12 19:15:27 +00005414 }
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005415}
jer.noble@apple.comd9d59ff2011-01-07 22:45:47 +00005416
jer.noble@apple.com43d325a2011-05-10 22:38:52 +00005417void Document::fullScreenElementRemoved()
5418{
jer.noble@apple.com548e3362011-06-18 20:34:57 +00005419 m_fullScreenElement->setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
jer.noble@apple.com7a362df2011-05-18 06:12:12 +00005420 webkitCancelFullScreen();
jer.noble@apple.com43d325a2011-05-10 22:38:52 +00005421}
5422
5423void Document::removeFullScreenElementOfSubtree(Node* node, bool amongChildrenOnly)
5424{
5425 if (!m_fullScreenElement)
5426 return;
5427
5428 bool elementInSubtree = false;
5429 if (amongChildrenOnly)
5430 elementInSubtree = m_fullScreenElement->isDescendantOf(node);
5431 else
5432 elementInSubtree = (m_fullScreenElement == node) || m_fullScreenElement->isDescendantOf(node);
5433
5434 if (elementInSubtree)
5435 fullScreenElementRemoved();
5436}
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005437
5438bool Document::isAnimatingFullScreen() const
5439{
5440 return m_isAnimatingFullScreen;
5441}
5442
5443void Document::setAnimatingFullScreen(bool flag)
5444{
5445 if (m_isAnimatingFullScreen == flag)
5446 return;
5447 m_isAnimatingFullScreen = flag;
5448
jer.noble@apple.com961d45b2011-05-26 19:30:48 +00005449 if (m_fullScreenElement && m_fullScreenElement->isDescendantOf(this)) {
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005450 m_fullScreenElement->setNeedsStyleRecalc();
darin@apple.com1628ed92011-05-29 20:12:01 +00005451 scheduleForcedStyleRecalc();
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005452 }
jer.noble@apple.comfed7d932011-05-23 22:22:27 +00005453}
jer.noble@apple.com26cf8702012-03-16 18:12:14 +00005454
5455void Document::clearFullscreenElementStack()
5456{
5457 m_fullScreenElementStack.clear();
5458}
5459
5460void Document::popFullscreenElementStack()
5461{
5462 if (m_fullScreenElementStack.isEmpty())
5463 return;
5464
5465 m_fullScreenElementStack.removeFirst();
5466}
5467
5468void Document::pushFullscreenElementStack(Element* element)
5469{
5470 m_fullScreenElementStack.prepend(element);
5471}
5472
5473void Document::addDocumentToFullScreenChangeEventQueue(Document* doc)
5474{
5475 ASSERT(doc);
5476 Node* target = doc->webkitFullscreenElement();
5477 if (!target)
5478 target = doc->webkitCurrentFullScreenElement();
5479 if (!target)
5480 target = doc;
5481 m_fullScreenChangeEventTargetQueue.append(target);
5482}
jer.noble@apple.comc5584f32010-08-27 20:49:02 +00005483#endif
beidson@apple.com992d69a2009-11-03 21:06:09 +00005484
scheib@chromium.org6ed01762012-06-12 03:02:16 +00005485#if ENABLE(POINTER_LOCK)
scheib@chromium.orgebbfecc2012-06-15 19:53:27 +00005486void Document::webkitExitPointerLock()
5487{
scheib@chromium.orgf4b6c5c2012-08-01 05:10:30 +00005488 if (!page())
5489 return;
5490 if (Element* target = page()->pointerLockController()->element()) {
5491 if (target->document() != this)
5492 return;
5493 }
5494 page()->pointerLockController()->requestPointerUnlock();
scheib@chromium.orgebbfecc2012-06-15 19:53:27 +00005495}
5496
scheib@chromium.org6ed01762012-06-12 03:02:16 +00005497Element* Document::webkitPointerLockElement() const
5498{
scheib@chromium.org575ba7c2012-09-05 17:31:32 +00005499 if (!page() || page()->pointerLockController()->lockPending())
scheib@chromium.orge31007f2012-07-23 15:50:29 +00005500 return 0;
5501 if (Element* element = page()->pointerLockController()->element()) {
5502 if (element->document() == this)
5503 return element;
5504 }
5505 return 0;
scheib@chromium.org6ed01762012-06-12 03:02:16 +00005506}
5507#endif
5508
eric.carlson@apple.com9c7fc722010-08-26 16:45:43 +00005509void Document::decrementLoadEventDelayCount()
5510{
5511 ASSERT(m_loadEventDelayCount);
5512 --m_loadEventDelayCount;
5513
jschuh@chromium.org47fb2f52010-10-04 22:25:43 +00005514 if (frame() && !m_loadEventDelayCount && !m_loadEventDelayTimer.isActive())
5515 m_loadEventDelayTimer.startOneShot(0);
5516}
5517
5518void Document::loadEventDelayTimerFired(Timer<Document>*)
5519{
5520 if (frame())
eric.carlson@apple.com9c7fc722010-08-26 16:45:43 +00005521 frame()->loader()->checkCompleted();
5522}
5523
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005524#if ENABLE(REQUEST_ANIMATION_FRAME)
commit-queue@webkit.org9fb90af2012-04-09 11:42:18 +00005525int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005526{
jamesr@google.com72acb832012-03-15 05:07:20 +00005527 if (!m_scriptedAnimationController) {
5528#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
dino@apple.com78a8b472012-04-05 21:29:38 +00005529 m_scriptedAnimationController = ScriptedAnimationController::create(this, page() ? page()->displayID() : 0);
jamesr@google.com72acb832012-03-15 05:07:20 +00005530#else
5531 m_scriptedAnimationController = ScriptedAnimationController::create(this, 0);
5532#endif
dino@apple.com78a8b472012-04-05 21:29:38 +00005533 // It's possible that the Page may have suspended scripted animations before
5534 // we were created. We need to make sure that we don't start up the animation
5535 // controller on a background tab, for example.
5536 if (!page() || page()->scriptedAnimationsSuspended())
5537 m_scriptedAnimationController->suspend();
jamesr@google.com72acb832012-03-15 05:07:20 +00005538 }
jamesr@google.com9f8b52b2011-02-16 00:53:36 +00005539
commit-queue@webkit.org9fb90af2012-04-09 11:42:18 +00005540 return m_scriptedAnimationController->registerCallback(callback);
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005541}
5542
commit-queue@webkit.orgcd5d11d2011-12-12 20:58:15 +00005543void Document::webkitCancelAnimationFrame(int id)
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005544{
jamesr@google.com9f8b52b2011-02-16 00:53:36 +00005545 if (!m_scriptedAnimationController)
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005546 return;
jamesr@google.com9f8b52b2011-02-16 00:53:36 +00005547 m_scriptedAnimationController->cancelCallback(id);
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005548}
5549
nduca@chromium.orgf98045a2012-05-07 17:37:30 +00005550void Document::serviceScriptedAnimations(DOMTimeStamp time)
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005551{
jamesr@google.com9f8b52b2011-02-16 00:53:36 +00005552 if (!m_scriptedAnimationController)
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005553 return;
nduca@chromium.orgf98045a2012-05-07 17:37:30 +00005554 m_scriptedAnimationController->serviceScriptedAnimations(time);
jamesr@google.com0ea9e5f2011-01-20 21:50:34 +00005555}
5556#endif
5557
benm@google.comb08424c2010-10-19 11:50:02 +00005558#if ENABLE(TOUCH_EVENTS)
commit-queue@webkit.org20bf23d2011-06-19 04:13:49 +00005559PassRefPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, int pageX, int pageY, int screenX, int screenY, int radiusX, int radiusY, float rotationAngle, float force, ExceptionCode&) const
benm@google.comb08424c2010-10-19 11:50:02 +00005560{
5561 // FIXME: It's not clear from the documentation at
5562 // http://developer.apple.com/library/safari/#documentation/UserExperience/Reference/DocumentAdditionsReference/DocumentAdditions/DocumentAdditions.html
5563 // when this method should throw and nor is it by inspection of iOS behavior. It would be nice to verify any cases where it throws under iOS
5564 // and implement them here. See https://bugs.webkit.org/show_bug.cgi?id=47819
benm@google.comb08424c2010-10-19 11:50:02 +00005565 Frame* frame = window ? window->frame() : this->frame();
commit-queue@webkit.org20bf23d2011-06-19 04:13:49 +00005566 return Touch::create(frame, target, identifier, screenX, screenY, pageX, pageY, radiusX, radiusY, rotationAngle, force);
benm@google.comb08424c2010-10-19 11:50:02 +00005567}
benm@google.comb08424c2010-10-19 11:50:02 +00005568#endif
5569
andersca@apple.com4ef10872012-02-06 00:43:19 +00005570static void wheelEventHandlerCountChanged(Document* document)
5571{
andersca@apple.com4ef10872012-02-06 00:43:19 +00005572 Page* page = document->page();
5573 if (!page)
5574 return;
5575
5576 ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator();
5577 if (!scrollingCoordinator)
5578 return;
5579
5580 FrameView* frameView = document->view();
5581 if (!frameView)
5582 return;
5583
5584 scrollingCoordinator->frameViewWheelEventHandlerCountChanged(frameView);
andersca@apple.com4ef10872012-02-06 00:43:19 +00005585}
5586
jonlee@apple.com8d909182011-05-16 17:25:02 +00005587void Document::didAddWheelEventHandler()
5588{
5589 ++m_wheelEventHandlerCount;
5590 Frame* mainFrame = page() ? page()->mainFrame() : 0;
5591 if (mainFrame)
5592 mainFrame->notifyChromeClientWheelEventHandlerCountChanged();
andersca@apple.com4ef10872012-02-06 00:43:19 +00005593
5594 wheelEventHandlerCountChanged(this);
jonlee@apple.com8d909182011-05-16 17:25:02 +00005595}
5596
5597void Document::didRemoveWheelEventHandler()
5598{
5599 ASSERT(m_wheelEventHandlerCount > 0);
5600 --m_wheelEventHandlerCount;
5601 Frame* mainFrame = page() ? page()->mainFrame() : 0;
5602 if (mainFrame)
5603 mainFrame->notifyChromeClientWheelEventHandlerCountChanged();
andersca@apple.com4ef10872012-02-06 00:43:19 +00005604
5605 wheelEventHandlerCountChanged(this);
jonlee@apple.com8d909182011-05-16 17:25:02 +00005606}
5607
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +00005608void Document::didAddTouchEventHandler()
5609{
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +00005610#if ENABLE(TOUCH_EVENTS)
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +00005611 ++m_touchEventHandlerCount;
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +00005612 if (m_touchEventHandlerCount > 1)
5613 return;
5614 if (Page* page = this->page())
5615 page->chrome()->client()->needTouchEvents(true);
5616#endif
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +00005617}
5618
5619void Document::didRemoveTouchEventHandler()
5620{
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +00005621#if ENABLE(TOUCH_EVENTS)
5622 ASSERT(m_touchEventHandlerCount);
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +00005623 --m_touchEventHandlerCount;
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +00005624 if (m_touchEventHandlerCount)
5625 return;
5626
pierre.rossi@gmail.com81b05962012-07-23 18:31:14 +00005627 Page* page = this->page();
5628 if (!page)
5629 return;
5630 for (const Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
5631 if (frame->document() && frame->document()->touchEventHandlerCount())
5632 return;
5633 }
5634 page->chrome()->client()->needTouchEvents(false);
5635#endif
commit-queue@webkit.org7c44a682012-02-15 20:21:15 +00005636}
5637
eric@webkit.org591bb232012-05-02 01:09:53 +00005638HTMLIFrameElement* Document::seamlessParentIFrame() const
5639{
5640 if (!shouldDisplaySeamlesslyWithParent())
5641 return 0;
5642
5643 HTMLFrameOwnerElement* ownerElement = this->ownerElement();
5644 ASSERT(ownerElement->hasTagName(iframeTag));
5645 return static_cast<HTMLIFrameElement*>(ownerElement);
5646}
5647
5648bool Document::shouldDisplaySeamlesslyWithParent() const
5649{
eric@webkit.orga1a6e122012-05-07 22:02:47 +00005650#if ENABLE(IFRAME_SEAMLESS)
eric@webkit.org591bb232012-05-02 01:09:53 +00005651 HTMLFrameOwnerElement* ownerElement = this->ownerElement();
5652 if (!ownerElement)
5653 return false;
5654 return m_mayDisplaySeamlessWithParent && ownerElement->hasTagName(iframeTag) && ownerElement->fastHasAttribute(seamlessAttr);
eric@webkit.orga1a6e122012-05-07 22:02:47 +00005655#else
5656 return false;
5657#endif
eric@webkit.org591bb232012-05-02 01:09:53 +00005658}
5659
beidson@apple.com197fbd32011-05-31 22:13:06 +00005660DocumentLoader* Document::loader() const
5661{
5662 if (!m_frame)
5663 return 0;
5664
jschuh@chromium.org2a6986e2011-11-08 17:42:29 +00005665 DocumentLoader* loader = m_frame->loader()->documentLoader();
beidson@apple.com197fbd32011-05-31 22:13:06 +00005666 if (!loader)
5667 return 0;
5668
5669 if (m_frame->document() != this)
5670 return 0;
5671
5672 return loader;
5673}
5674
rniwa@webkit.org43f105f2011-10-14 16:13:01 +00005675#if ENABLE(MICRODATA)
5676PassRefPtr<NodeList> Document::getItems(const String& typeNames)
5677{
rniwa@webkit.org43f105f2011-10-14 16:13:01 +00005678 // Since documet.getItem() is allowed for microdata, typeNames will be null string.
arko@motorola.coma89cb252012-08-06 10:29:39 +00005679 // In this case we need to create an empty string identifier to map such request in the cache.
arko@motorola.comc2218d72012-06-25 12:09:33 +00005680 String localTypeNames = typeNames.isNull() ? MicroDataItemList::undefinedItemType() : typeNames;
rniwa@webkit.org43f105f2011-10-14 16:13:01 +00005681
rniwa@webkit.orgfc3b7b72012-07-12 20:31:09 +00005682 return ensureRareData()->ensureNodeLists()->addCacheWithName<MicroDataItemList>(this, DynamicNodeList::MicroDataItemListType, localTypeNames);
rniwa@webkit.org43f105f2011-10-14 16:13:01 +00005683}
5684#endif
5685
commit-queue@webkit.orgc558b512012-03-27 19:19:59 +00005686IntSize Document::viewportSize() const
5687{
5688 if (!view())
5689 return IntSize();
5690 return view()->visibleContentRect(/* includeScrollbars */ true).size();
5691}
5692
jpu@apple.comdfd2ce62012-04-16 03:05:06 +00005693Node* eventTargetNodeForDocument(Document* doc)
5694{
5695 if (!doc)
5696 return 0;
5697 Node* node = doc->focusedNode();
5698 if (!node && doc->isPluginDocument()) {
5699 PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
5700 node = pluginDocument->pluginNode();
5701 }
5702 if (!node && doc->isHTMLDocument())
5703 node = doc->body();
5704 if (!node)
5705 node = doc->documentElement();
5706 return node;
5707}
5708
wangxianzhu@chromium.org254f3222012-06-07 06:57:19 +00005709void Document::adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(Vector<FloatQuad>& quads, RenderObject* renderer)
5710{
5711 if (!view())
5712 return;
5713
5714 float inverseFrameScale = 1;
5715 if (frame())
5716 inverseFrameScale = 1 / frame()->frameScaleFactor();
5717
5718 LayoutRect visibleContentRect = view()->visibleContentRect();
5719 for (size_t i = 0; i < quads.size(); ++i) {
5720 quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
5721 adjustFloatQuadForAbsoluteZoom(quads[i], renderer);
5722 if (inverseFrameScale != 1)
5723 quads[i].scale(inverseFrameScale, inverseFrameScale);
5724 }
5725}
5726
5727void Document::adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(FloatRect& rect, RenderObject* renderer)
5728{
5729 if (!view())
5730 return;
5731
5732 float inverseFrameScale = 1;
5733 if (frame())
5734 inverseFrameScale = 1 / frame()->frameScaleFactor();
5735
5736 LayoutRect visibleContentRect = view()->visibleContentRect();
5737 rect.move(-visibleContentRect.x(), -visibleContentRect.y());
5738 adjustFloatRectForAbsoluteZoom(rect, renderer);
5739 if (inverseFrameScale != 1)
5740 rect.scale(inverseFrameScale);
5741}
5742
morrita@google.comac743042012-06-13 08:05:43 +00005743void Document::setContextFeatures(PassRefPtr<ContextFeatures> features)
5744{
5745 m_contextFeatures = features;
5746}
5747
allan.jensen@nokia.com236eff22012-09-13 15:22:37 +00005748static RenderObject* nearestCommonHoverAncestor(RenderObject* obj1, RenderObject* obj2)
5749{
5750 if (!obj1 || !obj2)
5751 return 0;
5752
5753 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor()) {
5754 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor()) {
5755 if (currObj1 == currObj2)
5756 return currObj1;
5757 }
5758 }
5759
5760 return 0;
5761}
5762
5763void Document::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
5764{
5765 // We don't update :hover/:active state when the result is marked as readOnly.
5766 if (request.readOnly())
5767 return;
5768
5769 Node* innerNodeInDocument = result.innerNode();
allan.jensen@nokia.com82fb3052012-09-18 10:28:02 +00005770 ASSERT(!innerNodeInDocument || innerNodeInDocument->document() == this);
allan.jensen@nokia.com236eff22012-09-13 15:22:37 +00005771
5772 Node* oldActiveNode = activeNode();
5773 if (oldActiveNode && !request.active()) {
5774 // We are clearing the :active chain because the mouse has been released.
5775 for (RenderObject* curr = oldActiveNode->renderer(); curr; curr = curr->parent()) {
5776 if (curr->node() && !curr->isText()) {
5777 curr->node()->setActive(false);
5778 curr->node()->clearInActiveChain();
5779 }
5780 }
5781 setActiveNode(0);
5782 } else {
5783 Node* newActiveNode = innerNodeInDocument;
5784 if (!oldActiveNode && newActiveNode && request.active() && !request.touchMove()) {
5785 // We are setting the :active chain and freezing it. If future moves happen, they
5786 // will need to reference this chain.
5787 for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
5788 if (curr->node() && !curr->isText())
5789 curr->node()->setInActiveChain();
5790 }
5791 setActiveNode(newActiveNode);
5792 }
5793 }
5794 // If the mouse has just been pressed, set :active on the chain. Those (and only those)
5795 // nodes should remain :active until the mouse is released.
5796 bool allowActiveChanges = !oldActiveNode && activeNode();
5797
5798 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
5799 // :hover/:active to only apply to elements that are in the :active chain that we froze
5800 // at the time the mouse went down.
5801 bool mustBeInActiveChain = request.active() && request.move();
5802
5803 RefPtr<Node> oldHoverNode = hoverNode();
5804 // Clear the :hover chain when the touch gesture is over.
5805 if (request.touchRelease()) {
5806 if (oldHoverNode) {
5807 for (RenderObject* curr = oldHoverNode->renderer(); curr; curr = curr->hoverAncestor()) {
5808 if (curr->node() && !curr->isText())
5809 curr->node()->setHovered(false);
5810 }
5811 setHoverNode(0);
5812 }
5813 // A touch release can not set new hover or active target.
5814 return;
5815 }
5816
5817 // Check to see if the hovered node has changed.
5818 // If it hasn't, we do not need to do anything.
5819 Node* newHoverNode = innerNodeInDocument;
5820 while (newHoverNode && !newHoverNode->renderer())
5821 newHoverNode = newHoverNode->parentOrHostNode();
5822
5823 // Update our current hover node.
5824 setHoverNode(newHoverNode);
5825
5826 // We have two different objects. Fetch their renderers.
5827 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
5828 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
5829
5830 // Locate the common ancestor render object for the two renderers.
5831 RenderObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj);
5832
5833 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
5834 Vector<RefPtr<Node>, 32> nodesToAddToChain;
5835
5836 if (oldHoverObj != newHoverObj) {
5837 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
5838 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
5839 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
5840 nodesToRemoveFromChain.append(curr->node());
5841 }
5842 }
5843
5844 // Now set the hover state for our new object up to the root.
5845 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
5846 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
5847 nodesToAddToChain.append(curr->node());
5848 }
5849
5850 size_t removeCount = nodesToRemoveFromChain.size();
5851 for (size_t i = 0; i < removeCount; ++i)
5852 nodesToRemoveFromChain[i]->setHovered(false);
5853
5854 size_t addCount = nodesToAddToChain.size();
5855 for (size_t i = 0; i < addCount; ++i) {
5856 if (allowActiveChanges)
5857 nodesToAddToChain[i]->setActive(true);
5858 nodesToAddToChain[i]->setHovered(true);
5859 }
5860}
5861
yurys@chromium.org1a722c52012-07-06 11:25:28 +00005862void Document::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
5863{
loislo@chromium.org53b3ffd2012-09-05 15:11:06 +00005864 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
loislo@chromium.org24454d92012-08-03 16:44:40 +00005865 ContainerNode::reportMemoryUsage(memoryObjectInfo);
loislo@chromium.orgc10e0982012-09-26 14:10:50 +00005866 info.addMember(m_styleResolver);
loislo@chromium.org83736932012-09-25 07:54:44 +00005867 info.addMember(m_customFonts);
loislo@chromium.org61a7dd62012-09-17 15:12:21 +00005868 info.addMember(m_url);
5869 info.addMember(m_baseURL);
5870 info.addMember(m_baseURLOverride);
5871 info.addMember(m_baseElementURL);
5872 info.addMember(m_cookieURL);
5873 info.addMember(m_firstPartyForCookies);
5874 info.addMember(m_documentURI);
5875 info.addMember(m_baseTarget);
loislo@chromium.orgc10e0982012-09-26 14:10:50 +00005876 info.addMember(m_docType);
5877 info.addMember(m_implementation);
5878 info.addMember(m_elemSheet);
loislo@chromium.org61a7dd62012-09-17 15:12:21 +00005879 info.addMember(m_frame);
5880 info.addMember(m_cachedResourceLoader);
antti@apple.come5a88a72012-09-24 22:14:47 +00005881 info.addMember(m_styleSheetCollection);
loislo@chromium.orgc10e0982012-09-26 14:10:50 +00005882 info.addMember(m_styleSheetList);
5883 info.addMember(m_formController);
5884 info.addMember(m_nodeIterators);
5885 info.addMember(m_ranges);
loislo@chromium.org61a7dd62012-09-17 15:12:21 +00005886 info.addMember(m_title.string());
5887 info.addMember(m_rawTitle.string());
5888 info.addMember(m_xmlEncoding);
5889 info.addMember(m_xmlVersion);
5890 info.addMember(m_contentLanguage);
yurys@chromium.org9c990162012-10-01 14:46:25 +00005891 info.addMember(m_documentNamedItemCollections);
5892 info.addMember(m_windowNamedItemCollections);
yurys@chromium.org1a722c52012-07-06 11:25:28 +00005893#if ENABLE(DASHBOARD_SUPPORT)
loislo@chromium.org83736932012-09-25 07:54:44 +00005894 info.addMember(m_dashboardRegions);
yurys@chromium.org1a722c52012-07-06 11:25:28 +00005895#endif
yurys@chromium.org9c990162012-10-01 14:46:25 +00005896 info.addMember(m_cssCanvasElements);
loislo@chromium.org83736932012-09-25 07:54:44 +00005897 info.addMember(m_iconURLs);
loislo@chromium.orgc10e0982012-09-26 14:10:50 +00005898 info.addMember(m_documentSuspensionCallbackElements);
5899 info.addMember(m_mediaVolumeCallbackElements);
5900 info.addMember(m_privateBrowsingStateChangedElements);
yurys@chromium.org9c990162012-10-01 14:46:25 +00005901 info.addMember(m_elementsByAccessKey);
loislo@chromium.org61a7dd62012-09-17 15:12:21 +00005902 info.addMember(m_eventQueue);
loislo@chromium.orgc10e0982012-09-26 14:10:50 +00005903 info.addMember(m_mediaCanStartListeners);
loislo@chromium.org83736932012-09-25 07:54:44 +00005904 info.addMember(m_pendingTasks);
yurys@chromium.org1a722c52012-07-06 11:25:28 +00005905}
5906
commit-queue@webkit.org5deb7492012-06-09 09:05:22 +00005907#if ENABLE(UNDO_MANAGER)
5908PassRefPtr<UndoManager> Document::undoManager()
5909{
5910 if (!m_undoManager)
commit-queue@webkit.org290528b2012-08-22 01:42:43 +00005911 m_undoManager = UndoManager::create(this);
commit-queue@webkit.org5deb7492012-06-09 09:05:22 +00005912 return m_undoManager;
5913}
5914#endif
5915
kling@webkit.org7c575782012-09-04 02:19:26 +00005916class ImmutableAttributeDataCacheKey {
5917public:
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005918 ImmutableAttributeDataCacheKey(const QualifiedName& tagName, const Attribute* attributes, unsigned attributeCount)
5919 : m_tagQName(tagName)
kling@webkit.org7c575782012-09-04 02:19:26 +00005920 , m_attributes(attributes)
5921 , m_attributeCount(attributeCount)
5922 { }
5923
5924 bool operator!=(const ImmutableAttributeDataCacheKey& other) const
5925 {
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005926 if (m_tagQName != other.m_tagQName)
kling@webkit.org7c575782012-09-04 02:19:26 +00005927 return true;
5928 if (m_attributeCount != other.m_attributeCount)
5929 return true;
5930 return memcmp(m_attributes, other.m_attributes, sizeof(Attribute) * m_attributeCount);
5931 }
5932
5933 unsigned hash() const
5934 {
5935 unsigned attributeHash = StringHasher::hashMemory(m_attributes, m_attributeCount * sizeof(Attribute));
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005936 return WTF::pairIntHash(m_tagQName.localName().impl()->existingHash(), attributeHash);
kling@webkit.org7c575782012-09-04 02:19:26 +00005937 }
5938
5939private:
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005940 QualifiedName m_tagQName;
kling@webkit.org7c575782012-09-04 02:19:26 +00005941 const Attribute* m_attributes;
5942 unsigned m_attributeCount;
5943};
5944
5945struct ImmutableAttributeDataCacheEntry {
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005946 ImmutableAttributeDataCacheEntry(const ImmutableAttributeDataCacheKey& k, PassRefPtr<ElementAttributeData> v)
5947 : key(k)
5948 , value(v)
5949 { }
5950
kling@webkit.org7c575782012-09-04 02:19:26 +00005951 ImmutableAttributeDataCacheKey key;
5952 RefPtr<ElementAttributeData> value;
5953};
5954
5955PassRefPtr<ElementAttributeData> Document::cachedImmutableAttributeData(const Element* element, const Vector<Attribute>& attributes)
5956{
5957 ASSERT(!attributes.isEmpty());
5958
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005959 ImmutableAttributeDataCacheKey cacheKey(element->tagQName(), attributes.data(), attributes.size());
kling@webkit.org7c575782012-09-04 02:19:26 +00005960 unsigned cacheHash = cacheKey.hash();
5961
5962 ImmutableAttributeDataCache::iterator cacheIterator = m_immutableAttributeDataCache.add(cacheHash, nullptr).iterator;
5963 if (cacheIterator->second && cacheIterator->second->key != cacheKey)
5964 cacheHash = 0;
5965
5966 RefPtr<ElementAttributeData> attributeData;
5967 if (cacheHash && cacheIterator->second)
5968 attributeData = cacheIterator->second->value;
5969 else
5970 attributeData = ElementAttributeData::createImmutable(attributes);
5971
5972 if (!cacheHash || cacheIterator->second)
5973 return attributeData.release();
5974
kling@webkit.orgca1e2d42012-09-24 00:57:54 +00005975 cacheIterator->second = adoptPtr(new ImmutableAttributeDataCacheEntry(ImmutableAttributeDataCacheKey(element->tagQName(), attributeData->immutableAttributeArray(), attributeData->length()), attributeData));
kling@webkit.org7c575782012-09-04 02:19:26 +00005976
5977 return attributeData.release();
5978}
5979
antti@apple.come5a88a72012-09-24 22:14:47 +00005980bool Document::haveStylesheetsLoaded() const
5981{
5982 return !m_styleSheetCollection->hasPendingSheets() || m_ignorePendingStylesheets;
5983}
5984
tkent@chromium.org24b1fce2012-09-28 15:51:52 +00005985Localizer& Document::getCachedLocalizer(const AtomicString& locale)
tkent@chromium.orgaff3c932012-09-14 12:40:27 +00005986{
5987 AtomicString localeKey = locale;
5988 if (locale.isEmpty() || !RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled())
5989 localeKey = defaultLanguage();
5990 LocaleToLocalizerMap::AddResult result = m_localizerCache.add(localeKey, nullptr);
5991 if (result.isNewEntry)
5992 result.iterator->second = Localizer::create(localeKey);
5993 return *(result.iterator->second);
5994}
5995
weinig343b6ff2007-08-07 03:08:53 +00005996} // namespace WebCore