Frame.cpp 104 KB
Newer Older
darin's avatar
darin committed
1
2
3
4
5
6
7
8
/* This file is part of the KDE project
 *
 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
 *                     1999 Lars Knoll <knoll@kde.org>
 *                     1999 Antti Koivisto <koivisto@kde.org>
 *                     2000 Simon Hausmann <hausmann@kde.org>
 *                     2000 Stefan Schimanski <1Stein@gmx.de>
 *                     2001 George Staikos <staikos@kde.org>
9
 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
ap's avatar
ap committed
10
 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
darin's avatar
darin committed
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

mjs's avatar
mjs committed
28
#include "config.h"
mjs's avatar
mjs committed
29
#include "Frame.h"
darin's avatar
darin committed
30
#include "FramePrivate.h"
darin's avatar
darin committed
31

darin's avatar
darin committed
32
#include "ApplyStyleCommand.h"
darin's avatar
darin committed
33
#include "CSSComputedStyleDeclaration.h"
34
#include "CSSProperty.h"
35
#include "CSSPropertyNames.h"
36
37
#include "Cache.h"
#include "CachedCSSStyleSheet.h"
darin's avatar
darin committed
38
#include "DOMImplementation.h"
39
#include "DOMWindow.h"
40
#include "Decoder.h"
41
#include "DocLoader.h"
mjs's avatar
mjs committed
42
#include "DocumentType.h"
darin's avatar
darin committed
43
#include "EditingText.h"
weinig's avatar
   
weinig committed
44
#include "Event.h"
darin's avatar
darin committed
45
#include "EventNames.h"
46
#include "FloatRect.h"
darin's avatar
darin committed
47
#include "Frame.h"
darin's avatar
darin committed
48
#include "GraphicsContext.h"
49
#include "HTMLViewSourceDocument.h"
darin's avatar
darin committed
50
#include "HTMLFormElement.h"
51
#include "HTMLFrameElement.h"
darin's avatar
darin committed
52
#include "HTMLGenericFormElement.h"
darin's avatar
darin committed
53
#include "HTMLNames.h"
54
#include "HTMLObjectElement.h"
andersca's avatar
andersca committed
55
#include "ImageDocument.h"
weinig's avatar
   
weinig committed
56
#include "MediaFeatureNames.h"
darin's avatar
darin committed
57
#include "MouseEventWithHitTestResults.h"
darin's avatar
darin committed
58
#include "NodeList.h"
lweintraub's avatar
lweintraub committed
59
#include "Page.h"
weinig's avatar
   
weinig committed
60
#include "PlugInInfoStore.h"
darin's avatar
darin committed
61
#include "Plugin.h"
andersca's avatar
andersca committed
62
#include "PluginDocument.h"
63
#include "RenderPart.h"
darin's avatar
darin committed
64
#include "RenderTheme.h"
adele's avatar
adele committed
65
#include "RenderTextField.h"
66
#include "RenderView.h"
darin's avatar
darin committed
67
#include "SegmentedString.h"
andersca's avatar
andersca committed
68
#include "TextDocument.h"
darin's avatar
darin committed
69
#include "TextIterator.h"
darin's avatar
darin committed
70
#include "TypingCommand.h"
darin's avatar
darin committed
71
72
73
74
75
76
77
#include "cssstyleselector.h"
#include "htmlediting.h"
#include "kjs_window.h"
#include "markup.h"
#include "visible_units.h"
#include "xml_tokenizer.h"
#include "xmlhttprequest.h"
78
#include <math.h>
darin's avatar
darin committed
79
#include <sys/types.h>
darin's avatar
darin committed
80

darin's avatar
darin committed
81
82
83
#if !WIN32
#include <unistd.h>
#endif
84

darin's avatar
darin committed
85
86
87
#if SVG_SUPPORT
#include "SVGNames.h"
#include "XLinkNames.h"
88
#include "XMLNames.h"
89
#include "SVGDocumentExtensions.h"
eseidel's avatar
eseidel committed
90
#include "SVGDOMImplementation.h"
darin's avatar
darin committed
91
92
#endif

darin's avatar
darin committed
93
using namespace std;
darin's avatar
darin committed
94
95
96
97
98
99
100
101
102

using KJS::JSLock;
using KJS::JSValue;
using KJS::Location;
using KJS::PausedTimeouts;
using KJS::SavedProperties;
using KJS::SavedBuiltins;
using KJS::UString;
using KJS::Window;
darin's avatar
darin committed
103
104
105

namespace WebCore {

darin's avatar
darin committed
106
using namespace EventNames;
107
using namespace HTMLNames;
darin's avatar
darin committed
108

darin's avatar
darin committed
109
const double caretBlinkFrequency = 0.5;
adele's avatar
adele committed
110
const double autoscrollInterval = 0.1;
kocienda's avatar
kocienda committed
111

darin's avatar
darin committed
112
class UserStyleSheetLoader : public CachedObjectClient {
darin's avatar
darin committed
113
public:
darin's avatar
darin committed
114
115
    UserStyleSheetLoader(Frame* frame, const String& url, DocLoader* dl)
        : m_frame(frame)
darin's avatar
darin committed
116
        , m_cachedSheet(Cache::requestStyleSheet(dl, url, false, 0, ""))
darin's avatar
darin committed
117
    {
darin's avatar
darin committed
118
        m_cachedSheet->ref(this);
darin's avatar
darin committed
119
    }
darin's avatar
darin committed
120
    ~UserStyleSheetLoader()
darin's avatar
darin committed
121
    {
darin's avatar
darin committed
122
        m_cachedSheet->deref(this);
darin's avatar
darin committed
123
    }
darin's avatar
darin committed
124
private:
125
    virtual void setStyleSheet(const String& /*URL*/, const String& sheet)
darin's avatar
darin committed
126
    {
darin's avatar
darin committed
127
        m_frame->setUserStyleSheet(sheet.deprecatedString());
darin's avatar
darin committed
128
    }
darin's avatar
darin committed
129
    Frame* m_frame;
darin's avatar
darin committed
130
131
    CachedCSSStyleSheet* m_cachedSheet;
};
darin's avatar
darin committed
132

darin's avatar
darin committed
133
#ifndef NDEBUG
mjs's avatar
mjs committed
134
135
136
137
138
139
struct FrameCounter { 
    static int count; 
    ~FrameCounter() { if (count != 0) fprintf(stderr, "LEAK: %d Frame\n", count); }
};
int FrameCounter::count = 0;
static FrameCounter frameCounter;
darin's avatar
darin committed
140
#endif
mjs's avatar
mjs committed
141

andersca's avatar
andersca committed
142
static inline Frame* parentFromOwnerElement(Element* ownerElement)
mjs's avatar
mjs committed
143
{
andersca's avatar
andersca committed
144
    if (!ownerElement)
darin's avatar
darin committed
145
        return 0;
andersca's avatar
andersca committed
146
    return ownerElement->document()->frame();
darin's avatar
darin committed
147
148
}

andersca's avatar
andersca committed
149
150
Frame::Frame(Page* page, Element* ownerElement) 
    : d(new FramePrivate(page, parentFromOwnerElement(ownerElement), this, ownerElement))
darin's avatar
darin committed
151
152
153
154
155
156
{
    AtomicString::init();
    Cache::init();
    EventNames::init();
    HTMLNames::init();
    QualifiedName::init();
157
    MediaFeatureNames::init();
darin's avatar
darin committed
158
159
160
161

#if SVG_SUPPORT
    SVGNames::init();
    XLinkNames::init();
162
    XMLNames::init();
darin's avatar
darin committed
163
164
#endif

mjs's avatar
mjs committed
165
    // FIXME: Frames were originally created with a refcount of 1, leave this
darin's avatar
darin committed
166
    // ref call here until we can straighten that out.
mjs's avatar
mjs committed
167
    ref();
darin's avatar
darin committed
168
#ifndef NDEBUG
mjs's avatar
mjs committed
169
170
171
172
    ++FrameCounter::count;
#endif
}

mjs's avatar
mjs committed
173
Frame::~Frame()
darin's avatar
darin committed
174
{
darin's avatar
darin committed
175
    ASSERT(!d->m_lifeSupportTimer.isActive());
mjs's avatar
mjs committed
176

darin's avatar
darin committed
177
#ifndef NDEBUG
mjs's avatar
mjs committed
178
179
180
    --FrameCounter::count;
#endif

darin's avatar
darin committed
181
    cancelRedirection();
darin's avatar
darin committed
182

darin's avatar
darin committed
183
184
    if (!d->m_bComplete)
        closeURL();
darin's avatar
darin committed
185

darin's avatar
darin committed
186
    clear(false);
darin's avatar
darin committed
187

darin's avatar
darin committed
188
    if (d->m_jscript && d->m_jscript->haveInterpreter())
darin's avatar
darin committed
189
        if (Window* w = Window::retrieveWindow(this)) {
darin's avatar
darin committed
190
            w->disconnectFrame();
darin's avatar
darin committed
191
192
193
194
195
196
            // Must clear the window pointer, otherwise we will not
            // garbage-collect collect the window (inside the call to
            // delete d below).
            w = 0;
        }

ggaren's avatar
ggaren committed
197
198
199
    if (d->m_domWindow)
        d->m_domWindow->disconnectFrame();
            
darin's avatar
darin committed
200
201
202
203
204
    setOpener(0);
    HashSet<Frame*> openedBy = d->m_openedFrames;
    HashSet<Frame*>::iterator end = openedBy.end();
    for (HashSet<Frame*>::iterator it = openedBy.begin(); it != end; ++it)
        (*it)->setOpener(0);
andersca's avatar
andersca committed
205
    
darin's avatar
darin committed
206
207
208
209
    if (d->m_view) {
        d->m_view->hide();
        d->m_view->m_frame = 0;
    }
darin's avatar
darin committed
210
  
darin's avatar
darin committed
211
    ASSERT(!d->m_lifeSupportTimer.isActive());
mjs's avatar
mjs committed
212

darin's avatar
darin committed
213
214
215
    delete d->m_userStyleSheetLoader;
    delete d;
    d = 0;
darin's avatar
darin committed
216
217
}

218
bool Frame::didOpenURL(const KURL& url)
darin's avatar
darin committed
219
{
darin's avatar
darin committed
220
  if (d->m_scheduledRedirection == locationChangeScheduledDuringLoad) {
ggaren's avatar
ggaren committed
221
222
    // A redirect was shceduled before the document was created. This can happen
    // when one frame changes another frame's location.
rjw's avatar
rjw committed
223
224
225
    return false;
  }
  
darin's avatar
darin committed
226
  cancelRedirection();
kocienda's avatar
kocienda committed
227
  
kocienda's avatar
kocienda committed
228
  // clear last edit command
kocienda's avatar
kocienda committed
229
  d->m_lastEditCommand = EditCommandPtr();
kocienda's avatar
kocienda committed
230
  
darin's avatar
darin committed
231
  closeURL();
darin's avatar
darin committed
232

darin's avatar
darin committed
233
  d->m_bComplete = false;
mjs's avatar
mjs committed
234
  d->m_bLoadingMainResource = true;
darin's avatar
darin committed
235
236
  d->m_bLoadEventEmitted = false;

darin's avatar
darin committed
237
238
  d->m_kjsStatusBarText = String();
  d->m_kjsDefaultStatusBarText = String();
darin's avatar
darin committed
239

240
241
242
  d->m_bJScriptEnabled = d->m_settings->isJavaScriptEnabled();
  d->m_bJavaEnabled = d->m_settings->isJavaEnabled();
  d->m_bPluginsEnabled = d->m_settings->isPluginsEnabled();
darin's avatar
darin committed
243

mjs's avatar
mjs committed
244
  // initializing d->m_url to the new url breaks relative links when opening such a link after this call and _before_ begin() is called (when the first
darin's avatar
darin committed
245
  // data arrives) (Simon)
mjs's avatar
mjs committed
246
  d->m_url = url;
247
  if (d->m_url.protocol().startsWith("http") && !d->m_url.host().isEmpty() && d->m_url.path().isEmpty())
mjs's avatar
mjs committed
248
249
    d->m_url.setPath("/");
  d->m_workingURL = d->m_url;
darin's avatar
darin committed
250

darin's avatar
darin committed
251
  started();
darin's avatar
darin committed
252
253
254
255

  return true;
}

mjs's avatar
mjs committed
256
void Frame::didExplicitOpen()
mjs's avatar
mjs committed
257
258
259
{
  d->m_bComplete = false;
  d->m_bLoadEventEmitted = false;
ggaren's avatar
ggaren committed
260
261
262
263
264
265
    
  // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
  // from a subsequent window.document.open / window.document.write call. 
  // Cancelling redirection here works for all cases because document.open 
  // implicitly precedes document.write.
  cancelRedirection(); 
mjs's avatar
mjs committed
266
267
}

mjs's avatar
mjs committed
268
void Frame::stopLoading(bool sendUnload)
ggaren's avatar
ggaren committed
269
270
271
{
  if (d->m_doc && d->m_doc->tokenizer())
    d->m_doc->tokenizer()->stopParsing();
ap's avatar
ap committed
272
273
  
  d->m_metaData.clear();
darin's avatar
darin committed
274

275
  if (sendUnload) {
mjs's avatar
mjs committed
276
    if (d->m_doc) {
mjs's avatar
mjs committed
277
      if (d->m_bLoadEventEmitted && !d->m_bUnloadEventEmitted) {
mjs's avatar
mjs committed
278
279
        d->m_doc->dispatchWindowEvent(unloadEvent, false, false);
        if (d->m_doc)
280
281
282
          d->m_doc->updateRendering();
        d->m_bUnloadEventEmitted = true;
      }
darin's avatar
darin committed
283
    }
284
285
286
    
    if (d->m_doc && !d->m_doc->inPageCache())
      d->m_doc->removeAllEventListenersFromAllNodes();
darin's avatar
darin committed
287
  }
mjs's avatar
mjs committed
288

darin's avatar
darin committed
289
  d->m_bComplete = true; // to avoid calling completed() in finishedParsing() (David)
mjs's avatar
mjs committed
290
  d->m_bLoadingMainResource = false;
darin's avatar
darin committed
291
  d->m_bLoadEventEmitted = true; // don't want that one either
darin's avatar
darin committed
292
  d->m_cachePolicy = KIO::CC_Verify; // Why here?
darin's avatar
darin committed
293

294
  if (d->m_doc && d->m_doc->parsing()) {
darin's avatar
darin committed
295
    finishedParsing();
darin's avatar
darin committed
296
297
    d->m_doc->setParsing(false);
  }
eseidel's avatar
eseidel committed
298
  
darin's avatar
darin committed
299
300
  d->m_workingURL = KURL();

darin's avatar
darin committed
301
  if (Document *doc = d->m_doc.get()) {
adele's avatar
adele committed
302
    if (DocLoader *docLoader = doc->docLoader())
darin's avatar
darin committed
303
      Cache::loader()->cancelRequests(docLoader);
ap's avatar
ap committed
304
      XMLHttpRequest::cancelRequests(doc);
adele's avatar
adele committed
305
  }
darin's avatar
darin committed
306
307

  // tell all subframes to stop as well
mjs's avatar
mjs committed
308
  for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
mjs's avatar
mjs committed
309
      child->stopLoading(sendUnload);
darin's avatar
darin committed
310
311
312

  d->m_bPendingChildRedirection = false;

darin's avatar
darin committed
313
  cancelRedirection();
314
315
}

316
BrowserExtension *Frame::browserExtension() const
darin's avatar
darin committed
317
318
319
320
{
  return d->m_extension;
}

321
FrameView* Frame::view() const
darin's avatar
darin committed
322
{
323
324
325
326
327
328
    return d->m_view.get();
}

void Frame::setView(FrameView* view)
{
    d->m_view = view;
darin's avatar
darin committed
329
330
}

mjs's avatar
mjs committed
331
bool Frame::jScriptEnabled() const
darin's avatar
darin committed
332
{
333
    return d->m_bJScriptEnabled;
darin's avatar
darin committed
334
335
}

darin's avatar
darin committed
336
KJSProxy *Frame::jScript()
darin's avatar
darin committed
337
{
ggaren's avatar
ggaren committed
338
    if (!d->m_bJScriptEnabled)
eseidel's avatar
eseidel committed
339
        return 0;
darin's avatar
darin committed
340

eseidel's avatar
eseidel committed
341
    if (!d->m_jscript)
darin's avatar
darin committed
342
        d->m_jscript = new KJSProxy(this);
darin's avatar
darin committed
343

eseidel's avatar
eseidel committed
344
    return d->m_jscript;
darin's avatar
darin committed
345
346
}

darin's avatar
darin committed
347
static bool getString(JSValue* result, DeprecatedString& string)
mjs's avatar
mjs committed
348
{
darin's avatar
darin committed
349
350
351
352
353
354
    if (!result)
        return false;
    JSLock lock;
    UString ustring;
    if (!result->getString(ustring))
        return false;
darin's avatar
darin committed
355
    string = ustring;
darin's avatar
darin committed
356
    return true;
mjs's avatar
mjs committed
357
358
}

darin's avatar
darin committed
359
void Frame::replaceContentsWithScriptResult(const KURL& url)
darin's avatar
darin committed
360
{
darin's avatar
darin committed
361
    JSValue* ret = executeScript(0, KURL::decode_string(url.url().mid(strlen("javascript:"))));
darin's avatar
darin committed
362
    DeprecatedString scriptResult;
darin's avatar
darin committed
363
364
365
366
367
    if (getString(ret, scriptResult)) {
        begin();
        write(scriptResult);
        end();
    }
darin's avatar
darin committed
368
369
}

darin's avatar
darin committed
370
JSValue* Frame::executeScript(Node* n, const DeprecatedString& script, bool forceUserGesture)
darin's avatar
darin committed
371
{
darin's avatar
darin committed
372
  KJSProxy *proxy = jScript();
darin's avatar
darin committed
373

eseidel's avatar
eseidel committed
374
  if (!proxy)
darin's avatar
darin committed
375
376
    return 0;

darin's avatar
darin committed
377
  d->m_runningScripts++;
mjs's avatar
mjs committed
378
379
380
  // If forceUserGesture is true, then make the script interpreter
  // treat it as if triggered by a user gesture even if there is no
  // current DOM event being processed.
darin's avatar
darin committed
381
  JSValue* ret = proxy->evaluate(forceUserGesture ? DeprecatedString::null : d->m_url.url(), 0, script, n);
darin's avatar
darin committed
382
  d->m_runningScripts--;
darin's avatar
darin committed
383

darin's avatar
darin committed
384
  if (!d->m_runningScripts)
darin's avatar
darin committed
385
      submitFormAgain();
darin's avatar
darin committed
386

darin's avatar
darin committed
387
  Document::updateDocumentsRendering();
darin's avatar
darin committed
388
389
390
391

  return ret;
}

mjs's avatar
mjs committed
392
bool Frame::javaEnabled() const
darin's avatar
darin committed
393
{
394
    return d->m_settings->isJavaEnabled();
darin's avatar
darin committed
395
396
}

mjs's avatar
mjs committed
397
bool Frame::pluginsEnabled() const
darin's avatar
darin committed
398
{
399
    return d->m_bPluginsEnabled;
darin's avatar
darin committed
400
401
}

402
void Frame::setAutoloadImages(bool enable)
darin's avatar
darin committed
403
{
404
  if (d->m_doc && d->m_doc->docLoader()->autoloadImages() == enable)
darin's avatar
darin committed
405
406
    return;

407
408
  if (d->m_doc)
    d->m_doc->docLoader()->setAutoloadImages(enable);
darin's avatar
darin committed
409
410
}

mjs's avatar
mjs committed
411
bool Frame::autoloadImages() const
darin's avatar
darin committed
412
{
413
  if (d->m_doc)
darin's avatar
darin committed
414
415
416
417
418
    return d->m_doc->docLoader()->autoloadImages();

  return true;
}

mjs's avatar
mjs committed
419
void Frame::clear(bool clearWindowProperties)
darin's avatar
darin committed
420
{
421
  if (d->m_bCleared)
darin's avatar
darin committed
422
423
    return;
  d->m_bCleared = true;
mjs's avatar
mjs committed
424
  d->m_mousePressNode = 0;
darin's avatar
darin committed
425

mjs's avatar
mjs committed
426
427
  if (d->m_doc) {
    d->m_doc->cancelParsing();
darin's avatar
darin committed
428
    d->m_doc->detach();
mjs's avatar
mjs committed
429
  }
darin's avatar
darin committed
430
431

  // Moving past doc so that onUnload works.
darin's avatar
darin committed
432
433
  if (clearWindowProperties && d->m_jscript)
    d->m_jscript->clear();
darin's avatar
darin committed
434

435
  if (d->m_view)
darin's avatar
darin committed
436
437
    d->m_view->clear();

darin's avatar
darin committed
438
  // do not drop the document before the jscript and view are cleared, as some destructors
darin's avatar
darin committed
439
440
441
442
  // might still try to access the document.
  d->m_doc = 0;
  d->m_decoder = 0;

mjs's avatar
mjs committed
443
  d->m_plugins.clear();
darin's avatar
darin committed
444

darin's avatar
darin committed
445
  d->m_scheduledRedirection = noRedirectionScheduled;
darin's avatar
darin committed
446
  d->m_delayRedirect = 0;
darin's avatar
darin committed
447
448
  d->m_redirectURL = DeprecatedString::null;
  d->m_redirectReferrer = DeprecatedString::null;
darin's avatar
darin committed
449
  d->m_redirectLockHistory = true;
mjs's avatar
mjs committed
450
  d->m_redirectUserGesture = false;
darin's avatar
darin committed
451
452
453
454
455
  d->m_bHTTPRefresh = false;
  d->m_bFirstData = true;

  d->m_bMousePressed = false;

456
  if (!d->m_haveEncoding)
darin's avatar
darin committed
457
    d->m_encoding = DeprecatedString::null;
darin's avatar
darin committed
458
459
}

darin's avatar
darin committed
460
Document *Frame::document() const
darin's avatar
darin committed
461
{
darin's avatar
darin committed
462
463
    if (d)
        return d->m_doc.get();
darin's avatar
darin committed
464
465
466
    return 0;
}

darin's avatar
darin committed
467
void Frame::setDocument(Document* newDoc)
468
469
{
    if (d) {
darin's avatar
darin committed
470
        if (d->m_doc)
471
472
            d->m_doc->detach();
        d->m_doc = newDoc;
darin's avatar
darin committed
473
        if (newDoc)
eseidel's avatar
eseidel committed
474
            newDoc->attach();
475
476
477
    }
}

mjs's avatar
mjs committed
478
void Frame::receivedFirstData()
darin's avatar
darin committed
479
{
hyatt's avatar
hyatt committed
480
481
    begin(d->m_workingURL);

darin's avatar
darin committed
482
    d->m_doc->docLoader()->setCachePolicy(d->m_cachePolicy);
darin's avatar
darin committed
483
484
485
    d->m_workingURL = KURL();

    // When the first data arrives, the metadata has just been made available
darin's avatar
darin committed
486
    DeprecatedString qData;
darin's avatar
darin committed
487
488

    // Support for http-refresh
ap's avatar
ap committed
489
    qData = d->m_metaData.get("http-refresh").deprecatedString();
490
    if (!qData.isEmpty()) {
491
      double delay;
492
493
494
      int pos = qData.find(';');
      if (pos == -1)
        pos = qData.find(',');
darin's avatar
darin committed
495

496
      if (pos == -1) {
497
        delay = qData.stripWhiteSpace().toDouble();
trey's avatar
trey committed
498
        // We want a new history item if the refresh timeout > 1 second
499
500
        scheduleRedirection(delay, d->m_url.url(), delay <= 1);
      } else {
darin's avatar
darin committed
501
        int end_pos = qData.length();
502
        delay = qData.left(pos).stripWhiteSpace().toDouble();
503
504
        while (qData[++pos] == ' ');
        if (qData.find("url", pos, false) == pos) {
darin's avatar
darin committed
505
          pos += 3;
506
          while (qData[pos] == ' ' || qData[pos] == '=')
darin's avatar
darin committed
507
              pos++;
508
          if (qData[pos] == '"') {
darin's avatar
darin committed
509
510
              pos++;
              int index = end_pos-1;
511
512
              while (index > pos) {
                if (qData[index] == '"')
darin's avatar
darin committed
513
514
515
                    break;
                index--;
              }
516
              if (index > pos)
darin's avatar
darin committed
517
518
519
                end_pos = index;
          }
        }
trey's avatar
trey committed
520
        // We want a new history item if the refresh timeout > 1 second
521
        scheduleRedirection(delay, d->m_doc->completeURL(qData.mid(pos, end_pos)), delay <= 1);
darin's avatar
darin committed
522
523
524
525
526
      }
      d->m_bHTTPRefresh = true;
    }

    // Support for http last-modified
ap's avatar
ap committed
527
    d->m_lastModified = d->m_metaData.get("modified");
darin's avatar
darin committed
528
529
}

mjs's avatar
mjs committed
530
void Frame::childBegin()
trey's avatar
trey committed
531
{
mjs's avatar
mjs committed
532
533
534
    // We need to do this when the child is created so as to avoid the parent thining the child
    // is complete before it has even started loading.
    // FIXME: do we really still need this?
trey's avatar
trey committed
535
536
537
    d->m_bComplete = false;
}

mjs's avatar
mjs committed
538
539
540
541
542
543
544
545
546
547
void Frame::setResourceRequest(const ResourceRequest& request)
{
    d->m_request = request;
}

const ResourceRequest& Frame::resourceRequest() const
{
    return d->m_request;
}

548
void Frame::begin(const KURL& url)
darin's avatar
darin committed
549
{
ggaren's avatar
ggaren committed
550
551
  if (d->m_workingURL.isEmpty())
    createEmptyDocument(); // Creates an empty document if we don't have one already
mjs's avatar
mjs committed
552

darin's avatar
darin committed
553
  clear();
554
  partClearedInBegin();
rjw's avatar
WebKit:    
rjw committed
555

darin's avatar
darin committed
556
557
558
  d->m_bCleared = false;
  d->m_bComplete = false;
  d->m_bLoadEventEmitted = false;
mjs's avatar
mjs committed
559
  d->m_bLoadingMainResource = true;
darin's avatar
darin committed
560

darin's avatar
darin committed
561
  KURL ref(url);
darin's avatar
darin committed
562
563
564
  ref.setUser(DeprecatedString());
  ref.setPass(DeprecatedString());
  ref.setRef(DeprecatedString());
mjs's avatar
mjs committed
565
  d->m_referrer = ref.url();
mjs's avatar
mjs committed
566
  d->m_url = url;
darin's avatar
darin committed
567
568
  KURL baseurl;

569
  // We don't need KDE chained URI handling or window caption setting
mjs's avatar
mjs committed
570
571
  if (!d->m_url.isEmpty())
    baseurl = d->m_url;
darin's avatar
darin committed
572

eseidel's avatar
eseidel committed
573
574
575
576
577
#if SVG_SUPPORT
  if (d->m_request.m_responseMIMEType == "image/svg+xml")
    d->m_doc = SVGDOMImplementation::instance()->createDocument(d->m_view.get());
  else
#endif
darin's avatar
darin committed
578
579
  if (DOMImplementation::isXMLMIMEType(d->m_request.m_responseMIMEType))
    d->m_doc = DOMImplementation::instance()->createDocument(d->m_view.get());
andersca's avatar
andersca committed
580
  else if (DOMImplementation::isTextMIMEType(d->m_request.m_responseMIMEType))
andersca's avatar
andersca committed
581
    d->m_doc = new TextDocument(DOMImplementation::instance(), d->m_view.get());
andersca's avatar
andersca committed
582
  else if (Image::supportsType(d->m_request.m_responseMIMEType))
andersca's avatar
andersca committed
583
    d->m_doc = new ImageDocument(DOMImplementation::instance(), d->m_view.get());
andersca's avatar
andersca committed
584
585
  else if (PlugInInfoStore::supportsMIMEType(d->m_request.m_responseMIMEType))
    d->m_doc = new PluginDocument(DOMImplementation::instance(), d->m_view.get());
586
587
  else if (inViewSourceMode())
    d->m_doc = new HTMLViewSourceDocument(DOMImplementation::instance(), d->m_view.get());
mjs's avatar
mjs committed
588
  else
hyatt's avatar
hyatt committed
589
    d->m_doc = DOMImplementation::instance()->createHTMLDocument(d->m_view.get());
darin's avatar
darin committed
590
591

  if (!d->m_doc->attached())
592
593
    d->m_doc->attach();
  d->m_doc->setURL(d->m_url.url());
mjs's avatar
mjs committed
594
  // We prefer m_baseURL over d->m_url because d->m_url changes when we are
darin's avatar
darin committed
595
  // about to load a new page.
596
  d->m_doc->setBaseURL(baseurl.url());
darin's avatar
darin committed
597
  if (d->m_decoder)
eseidel's avatar
eseidel committed
598
    d->m_doc->setDecoder(d->m_decoder.get());
darin's avatar
darin committed
599

600
  updatePolicyBaseURL();
601

602
  setAutoloadImages(d->m_settings->autoLoadImages());
603
  const KURL& userStyleSheet = d->m_settings->userStyleSheetLocation();
rjw's avatar
WebKit:    
rjw committed
604

605
  if (!userStyleSheet.isEmpty())
darin's avatar
darin committed
606
    setUserStyleSheetLocation(KURL(userStyleSheet));
darin's avatar
darin committed
607

608
  restoreDocumentState();
609

mjs's avatar
mjs committed
610
  d->m_doc->implicitOpen();
darin's avatar
darin committed
611
  // clear widget
mjs's avatar
mjs committed
612
  if (d->m_view)
613
    d->m_view->resizeContents(0, 0);
darin's avatar
darin committed
614
615
}

mjs's avatar
mjs committed
616
void Frame::write(const char* str, int len)
darin's avatar
darin committed
617
{
andersca's avatar
andersca committed
618
619
620
621
622
623
624
625
626
627
628
629
630
    if (len == 0)
        return;
    
    if (len == -1)
        len = strlen(str);

    if (Tokenizer* t = d->m_doc->tokenizer()) {
        if (t->wantsRawData()) {
            t->writeRawData(str, len);
            return;
        }
    }
    
631
    if (!d->m_decoder) {
darin's avatar
darin committed
632
        d->m_decoder = new Decoder;
darin's avatar
darin committed
633
        if (!d->m_encoding.isNull())
mjs's avatar
mjs committed
634
            d->m_decoder->setEncodingName(d->m_encoding.latin1(),
darin's avatar
darin committed
635
                d->m_haveEncoding ? Decoder::UserChosenEncoding : Decoder::EncodingFromHTTPHeader);
ap's avatar
ap committed
636
        else
mjs's avatar
mjs committed
637
            d->m_decoder->setEncodingName(settings()->encoding().latin1(), Decoder::DefaultEncoding);
ap's avatar
ap committed
638

darin's avatar
darin committed
639
        if (d->m_doc)
eseidel's avatar
eseidel committed
640
            d->m_doc->setDecoder(d->m_decoder.get());
darin's avatar
darin committed
641
    }
642
  DeprecatedString decoded = d->m_decoder->decode(str, len);
darin's avatar
darin committed
643

644
645
  if (decoded.isEmpty())
    return;
darin's avatar
darin committed
646

647
  if (d->m_bFirstData) {
darin's avatar
darin committed
648
      // determine the parse mode
649
      d->m_doc->determineParseMode(decoded);
darin's avatar
darin committed
650
651
      d->m_bFirstData = false;

darin's avatar
darin committed
652
      // ### this is still quite hacky, but should work a lot better than the old solution
653
654
      if (d->m_decoder->visuallyOrdered()) d->m_doc->setVisuallyOrdered();
      d->m_doc->recalcStyle(Node::Force);
darin's avatar
darin committed
655
656
  }

andersca's avatar
andersca committed
657
658
  if (Tokenizer* t = d->m_doc->tokenizer()) {
      ASSERT(!t->wantsRawData());
659
      t->write(decoded, true);
andersca's avatar
andersca committed
660
  }
darin's avatar
darin committed
661
662
}

663
void Frame::write(const DeprecatedString& str)
darin's avatar
darin committed
664
{
665
  if (str.isNull())
darin's avatar
darin committed
666
667
    return;

668
  if (d->m_bFirstData) {
darin's avatar
darin committed
669
      // determine the parse mode
670
      d->m_doc->setParseMode(Document::Strict);
darin's avatar
darin committed
671
672
673
      d->m_bFirstData = false;
  }
  Tokenizer* t = d->m_doc->tokenizer();
674
675
  if (t)
    t->write(str, true);
darin's avatar
darin committed
676
677
}

mjs's avatar
mjs committed
678
void Frame::end()
darin's avatar
darin committed
679
{
mjs's avatar
mjs committed
680
681
682
683
    d->m_bLoadingMainResource = false;
    endIfNotLoading();
}

mjs's avatar
mjs committed
684
void Frame::endIfNotLoading()
mjs's avatar
mjs committed
685
686
687
688
{
    if (d->m_bLoadingMainResource)
        return;

darin's avatar
darin committed
689
    // make sure nothing's left in there...
mjs's avatar
mjs committed
690
    if (d->m_doc) {
ap's avatar
ap committed
691
692
693
694
695
696
697
698
        if (d->m_decoder) {
            DeprecatedString decoded = d->m_decoder->flush();
            if (d->m_bFirstData) {
                d->m_doc->determineParseMode(decoded);
                d->m_bFirstData = false;
            }
            write(decoded);
        }
ggaren's avatar
ggaren committed
699
        d->m_doc->finishParsing();
mjs's avatar
mjs committed
700
    } else
trey's avatar
trey committed
701
702
703
704
705
        // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
        // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
        // become true.  An example is when a subframe is a pure text doc, and that subframe is the
        // last one to complete.
        checkCompleted();
darin's avatar
darin committed
706
707
}

mjs's avatar
mjs committed
708
void Frame::stop()
709
{
ggaren's avatar
ggaren committed
710
711
712
713
    if (d->m_doc) {
        if (d->m_doc->tokenizer())
            d->m_doc->tokenizer()->stopParsing();
        d->m_doc->finishParsing();
mjs's avatar
mjs committed
714
715
716
717
718
719
    } else
        // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
        // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
        // become true.  An example is when a subframe is a pure text doc, and that subframe is the
        // last one to complete.
        checkCompleted();
720
721
}

mjs's avatar
mjs committed
722
void Frame::gotoAnchor()
darin's avatar
darin committed
723
{
724
    // If our URL has no ref, then we have no place we need to jump to.
mjs's avatar
mjs committed
725
    if (!d->m_url.hasRef())
726
727
        return;

darin's avatar
darin committed
728
    DeprecatedString ref = d->m_url.encodedHtmlRef();
vicki's avatar
vicki committed
729
730
731
732
733
    if (!gotoAnchor(ref)) {
        // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
        // Decoding here has to match encoding in completeURL, which means it has to use the
        // page's encoding rather than UTF-8.
        if (d->m_decoder)
mjs's avatar
mjs committed
734
            gotoAnchor(KURL::decode_string(ref, d->m_decoder->encoding()));
darin's avatar
darin committed
735
736
737
    }
}

darin's avatar
darin committed
738
void Frame::finishedParsing()
darin's avatar
darin committed
739
{
mjs's avatar
mjs committed
740
  RefPtr<Frame> protector(this);
hyatt's avatar
hyatt committed
741
742
  checkCompleted();

darin's avatar
darin committed
743
744
745
  if (!d->m_view)
    return; // We are being destroyed by something checkCompleted called.

darin's avatar
darin committed
746
747
748
749
  // check if the scrollbars are really needed for the content
  // if not, remove them, relayout, and repaint

  d->m_view->restoreScrollBar();
darin's avatar
darin committed
750
  gotoAnchor();
darin's avatar
darin committed
751
752
}

darin's avatar
darin committed
753
void Frame::loadDone()
darin's avatar
darin committed
754
{
darin's avatar
darin committed
755
756
    if (d->m_doc)
        checkCompleted();
darin's avatar
darin committed
757
758
}

mjs's avatar
mjs committed
759
void Frame::checkCompleted()
darin's avatar
darin committed
760
761
{
  // Any frame that hasn't completed yet ?
mjs's avatar
mjs committed
762
  for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
mjs's avatar
mjs committed
763
764
      if (!child->d->m_bComplete)
          return;
darin's avatar
darin committed
765

mjs's avatar
mjs committed
766
  // Have we completed before?
mjs's avatar
mjs committed
767
768
  if (d->m_bComplete)
      return;
mjs's avatar
mjs committed
769
770

  // Are we still parsing?
mjs's avatar
mjs committed
771
772
  if (d->m_doc && d->m_doc->parsing())
      return;
mjs's avatar
mjs committed
773

darin's avatar
darin committed
774
775
  // Still waiting for images/scripts from the loader ?
  int requests = 0;
mjs's avatar
mjs committed
776
777
  if (d->m_doc && d->m_doc->docLoader())
      requests = Cache::loader()->numRequests(d->m_doc->docLoader());
darin's avatar
darin committed
778

mjs's avatar
mjs committed
779
780
  if (requests > 0)
      return;
darin's avatar
darin committed
781
782
783
784
785
786
787

  // OK, completed.
  // Now do what should be done when we are really completed.
  d->m_bComplete = true;

  checkEmitLoadEvent(); // if we didn't do it before

mjs's avatar
mjs committed
788
789
790
  if (d->m_scheduledRedirection != noRedirectionScheduled) {
      // Do not start redirection for frames here! That action is
      // deferred until the parent emits a completed signal.
mjs's avatar
mjs committed
791
      if (!tree()->parent())
mjs's avatar
mjs committed
792
          startRedirectionTimer();
darin's avatar
darin committed
793

darin's avatar
darin committed
794
      completed(true);
mjs's avatar
mjs committed
795
  } else {
darin's avatar
darin committed
796
      completed(d->m_bPendingChildRedirection);
darin's avatar
darin committed
797
798
799
  }
}

mjs's avatar
mjs committed
800
void Frame::checkEmitLoadEvent()
darin's avatar
darin committed
801
{
mjs's avatar
mjs committed
802
803
    if (d->m_bLoadEventEmitted || !d->m_doc || d->m_doc->parsing())
        return;
darin's avatar
darin committed
804

mjs's avatar
mjs committed
805
    for (Frame* child = tree()->firstChild(); child; child = child->tree()->nextSibling())
mjs's avatar
mjs committed
806
807
        if (!child->d->m_bComplete) // still got a frame running -> too early
            return;
darin's avatar
darin committed
808

mjs's avatar
mjs committed
809
810
811