Page.cpp 48.9 KB
Newer Older
mjs's avatar
mjs committed
1
/*
2
 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All Rights Reserved.
3
 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
mjs's avatar
mjs committed
4 5 6 7 8 9 10 11 12 13 14 15
 *
 * 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
ddkilzer's avatar
ddkilzer committed
16 17
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
mjs's avatar
mjs committed
18 19 20 21
 */

#include "config.h"
#include "Page.h"
darin's avatar
darin committed
22

23
#include "AlternativeTextClient.h"
24
#include "AnimationController.h"
25
#include "BackForwardController.h"
26
#include "BackForwardList.h"
aroben's avatar
aroben committed
27
#include "Chrome.h"
ggaren's avatar
ggaren committed
28
#include "ChromeClient.h"
29
#include "ClientRectList.h"
aroben's avatar
aroben committed
30
#include "ContextMenuClient.h"
aroben's avatar
aroben committed
31
#include "ContextMenuController.h"
32
#include "DOMWindow.h"
33
#include "DocumentMarkerController.h"
34
#include "DocumentStyleSheetCollection.h"
35
#include "DragController.h"
36
#include "Editor.h"
darin@apple.com's avatar
darin@apple.com committed
37
#include "EditorClient.h"
38
#include "Event.h"
39 40
#include "EventNames.h"
#include "ExceptionCode.h"
41
#include "ExceptionCodePlaceholder.h"
42
#include "FileSystem.h"
43
#include "FocusController.h"
mjs's avatar
mjs committed
44
#include "Frame.h"
darin's avatar
darin committed
45
#include "FrameLoader.h"
jhoneycutt@apple.com's avatar
jhoneycutt@apple.com committed
46
#include "FrameLoaderClient.h"
47
#include "FrameSelection.h"
darin's avatar
darin committed
48
#include "FrameTree.h"
beidson's avatar
beidson committed
49
#include "FrameView.h"
darin@apple.com's avatar
darin@apple.com committed
50
#include "HTMLElement.h"
51
#include "HistoryController.h"
beidson's avatar
beidson committed
52
#include "HistoryItem.h"
53
#include "InspectorController.h"
54
#include "InspectorInstrumentation.h"
ggaren's avatar
ggaren committed
55
#include "Logging.h"
56
#include "MediaCanStartListener.h"
57
#include "Navigator.h"
darin@apple.com's avatar
darin@apple.com committed
58
#include "NetworkStateNotifier.h"
59
#include "PageCache.h"
60
#include "PageConsole.h"
darin@apple.com's avatar
darin@apple.com committed
61
#include "PageGroup.h"
62
#include "PlugInClient.h"
63
#include "PluginData.h"
64
#include "PluginView.h"
65
#include "PointerLockController.h"
andersca's avatar
andersca committed
66
#include "ProgressTracker.h"
67
#include "RenderArena.h"
68
#include "RenderTheme.h"
69
#include "RenderView.h"
70
#include "RenderWidget.h"
71
#include "RuntimeEnabledFeatures.h"
72
#include "SchemeRegistry.h"
73
#include "ScriptController.h"
74
#include "ScrollingCoordinator.h"
ggaren's avatar
ggaren committed
75
#include "Settings.h"
76
#include "SharedBuffer.h"
77 78
#include "StorageArea.h"
#include "StorageNamespace.h"
79
#include "TextResourceDecoder.h"
80
#include "VisitedLinkState.h"
81
#include "VoidCallback.h"
82
#include "WebCoreMemoryInstrumentation.h"
ggaren's avatar
ggaren committed
83
#include "Widget.h"
mjs's avatar
mjs committed
84
#include <wtf/HashMap.h>
85
#include <wtf/RefCountedLeakCounter.h>
86
#include <wtf/StdLibExtras.h>
87
#include <wtf/text/Base64.h>
88
#include <wtf/text/StringHash.h>
mjs's avatar
mjs committed
89

darin's avatar
darin committed
90 91
namespace WebCore {

darin's avatar
darin committed
92
static HashSet<Page*>* allPages;
mjs's avatar
mjs committed
93

94
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
ggaren's avatar
ggaren committed
95

96 97 98 99 100 101 102 103 104
static void networkStateChanged()
{
    Vector<RefPtr<Frame> > frames;
    
    // Get all the frames of all the pages in all the page groups
    HashSet<Page*>::iterator end = allPages->end();
    for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
            frames.append(frame);
105
        InspectorInstrumentation::networkStateChanged(*it);
106 107
    }

ap@webkit.org's avatar
ap@webkit.org committed
108
    AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
weinig@apple.com's avatar
weinig@apple.com committed
109
    for (unsigned i = 0; i < frames.size(); i++)
110
        frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
111
}
mitz@apple.com's avatar
mitz@apple.com committed
112

113 114 115 116 117 118 119 120 121 122
float deviceScaleFactor(Frame* frame)
{
    if (!frame)
        return 1;
    Page* page = frame->page();
    if (!page)
        return 1;
    return page->deviceScaleFactor();
}

123
Page::Page(PageClients& pageClients)
124 125
    : m_chrome(Chrome::create(this, pageClients.chromeClient))
    , m_dragCaretController(DragCaretController::create())
bolsinga@apple.com's avatar
bolsinga@apple.com committed
126
#if ENABLE(DRAG_SUPPORT)
127
    , m_dragController(DragController::create(this, pageClients.dragClient))
bolsinga@apple.com's avatar
bolsinga@apple.com committed
128
#endif
129
    , m_focusController(FocusController::create(this))
bolsinga@apple.com's avatar
bolsinga@apple.com committed
130
#if ENABLE(CONTEXT_MENUS)
131
    , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
bolsinga@apple.com's avatar
bolsinga@apple.com committed
132
#endif
bolsinga@apple.com's avatar
bolsinga@apple.com committed
133
#if ENABLE(INSPECTOR)
134
    , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
135
#endif
136 137
#if ENABLE(POINTER_LOCK)
    , m_pointerLockController(PointerLockController::create(this))
bolsinga@apple.com's avatar
bolsinga@apple.com committed
138
#endif
139 140 141
    , m_settings(Settings::create(this))
    , m_progress(ProgressTracker::create())
    , m_backForwardController(BackForwardController::create(this, pageClients.backForwardClient))
aroben@apple.com's avatar
aroben@apple.com committed
142
    , m_theme(RenderTheme::themeForPage(this))
143
    , m_editorClient(pageClients.editorClient)
144
    , m_plugInClient(pageClients.plugInClient)
145
    , m_validationMessageClient(pageClients.validationMessageClient)
146
    , m_subframeCount(0)
147
    , m_openedByDOM(false)
adele's avatar
adele committed
148
    , m_tabKeyCyclesThroughElements(true)
ggaren's avatar
ggaren committed
149
    , m_defersLoading(false)
150
    , m_defersLoadingCallCount(0)
hyatt's avatar
hyatt committed
151
    , m_inLowQualityInterpolationMode(false)
mitz@apple.com's avatar
mitz@apple.com committed
152
    , m_cookieEnabled(true)
darin@apple.com's avatar
darin@apple.com committed
153
    , m_areMemoryCacheClientCallsEnabled(true)
mitz@apple.com's avatar
mitz@apple.com committed
154
    , m_mediaVolume(1)
155
    , m_pageScaleFactor(1)
156
    , m_deviceScaleFactor(1)
157
    , m_suppressScrollbarAnimations(false)
158 159
    , m_didLoadUserStyleSheet(false)
    , m_userStyleSheetModificationTime(0)
darin@apple.com's avatar
darin@apple.com committed
160
    , m_group(0)
161
    , m_debugger(0)
weinig@apple.com's avatar
weinig@apple.com committed
162 163
    , m_customHTMLTokenizerTimeDelay(-1)
    , m_customHTMLTokenizerChunkSize(-1)
164
    , m_canStartMedia(true)
165
#if ENABLE(VIEW_MODE_CSS_MEDIA)
166
    , m_viewMode(ViewModeWindowed)
167
#endif // ENABLE(VIEW_MODE_CSS_MEDIA)
168
    , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
169
    , m_timerAlignmentInterval(Settings::defaultDOMTimerAlignmentInterval())
170
    , m_isEditable(false)
171
    , m_isOnscreen(true)
172
    , m_isInWindow(true)
173 174 175
#if ENABLE(PAGE_VISIBILITY_API)
    , m_visibilityState(PageVisibilityStateVisible)
#endif
176
    , m_displayID(0)
177
    , m_requestedLayoutMilestones(0)
178
    , m_isCountingRelevantRepaintedObjects(false)
179 180 181
#ifndef NDEBUG
    , m_isPainting(false)
#endif
182
    , m_alternativeTextClient(pageClients.alternativeTextClient)
183
    , m_scriptedAnimationsSuspended(false)
184
    , m_console(PageConsole::create(this))
mjs's avatar
mjs committed
185
{
186 187
    ASSERT(m_editorClient);

darin's avatar
darin committed
188 189
    if (!allPages) {
        allPages = new HashSet<Page*>;
190 191
        
        networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
darin's avatar
darin committed
192
    }
ggaren's avatar
ggaren committed
193

darin's avatar
darin committed
194 195
    ASSERT(!allPages->contains(this));
    allPages->add(this);
ggaren's avatar
ggaren committed
196 197

#ifndef NDEBUG
198
    pageCounter.increment();
ggaren's avatar
ggaren committed
199
#endif
mjs's avatar
mjs committed
200 201
}

darin's avatar
darin committed
202
Page::~Page()
darin's avatar
darin committed
203
{
darin's avatar
darin committed
204
    m_mainFrame->setView(0);
darin's avatar
darin committed
205
    setGroupName(String());
darin's avatar
darin committed
206
    allPages->remove(this);
207
    
208 209
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        frame->willDetachPage();
210
        frame->detachFromPage();
211
    }
212

ggaren's avatar
ggaren committed
213
    m_editorClient->pageDestroyed();
214 215
    if (m_plugInClient)
        m_plugInClient->pageDestroyed();
216 217
    if (m_alternativeTextClient)
        m_alternativeTextClient->pageDestroyed();
218

219 220 221
#if ENABLE(INSPECTOR)
    m_inspectorController->inspectedPageDestroyed();
#endif
ggaren's avatar
ggaren committed
222

223 224
    if (m_scrollingCoordinator)
        m_scrollingCoordinator->pageDestroyed();
225

226
    backForward()->close();
ggaren's avatar
ggaren committed
227

mjs's avatar
mjs committed
228
#ifndef NDEBUG
229
    pageCounter.decrement();
mjs's avatar
mjs committed
230
#endif
231

mjs's avatar
mjs committed
232
}
darin's avatar
darin committed
233

234
ArenaSize Page::renderTreeSize() const
235
{
236
    ArenaSize total(0, 0);
237
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
238 239 240 241 242 243
        if (!frame->document())
            continue;
        if (RenderArena* arena = frame->document()->renderArena()) {
            total.treeSize += arena->totalRenderArenaSize();
            total.allocated += arena->totalRenderArenaAllocatedBytes();
        }
244
    }
245
    return total;
246 247
}

248 249 250 251 252
ViewportArguments Page::viewportArguments() const
{
    return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportArguments() : ViewportArguments();
}

253 254 255 256 257 258 259 260
ScrollingCoordinator* Page::scrollingCoordinator()
{
    if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
        m_scrollingCoordinator = ScrollingCoordinator::create(this);

    return m_scrollingCoordinator.get();
}

261 262 263 264 265 266 267 268 269 270 271
String Page::scrollingStateTreeAsText()
{
    if (Document* document = m_mainFrame->document())
        document->updateLayout();

    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        return scrollingCoordinator->scrollingStateTreeAsText();

    return String();
}

272 273 274 275 276 277 278 279 280 281 282
String Page::mainThreadScrollingReasonsAsText()
{
    if (Document* document = m_mainFrame->document())
        document->updateLayout();

    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        return scrollingCoordinator->mainThreadScrollingReasonsAsText();

    return String();
}

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
{
    if (Document* document = m_mainFrame->document())
        document->updateLayout();

    Vector<IntRect> rects;
    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        rects = scrollingCoordinator->computeNonFastScrollableRegion(frame, IntPoint()).rects();

    Vector<FloatQuad> quads(rects.size());
    for (size_t i = 0; i < rects.size(); ++i)
        quads[i] = FloatRect(rects[i]);
    return ClientRectList::create(quads);
}

298
#if ENABLE(VIEW_MODE_CSS_MEDIA)
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
struct ViewModeInfo {
    const char* name;
    Page::ViewMode type;
};
static const int viewModeMapSize = 5;
static ViewModeInfo viewModeMap[viewModeMapSize] = {
    {"windowed", Page::ViewModeWindowed},
    {"floating", Page::ViewModeFloating},
    {"fullscreen", Page::ViewModeFullscreen},
    {"maximized", Page::ViewModeMaximized},
    {"minimized", Page::ViewModeMinimized}
};

Page::ViewMode Page::stringToViewMode(const String& text)
{
    for (int i = 0; i < viewModeMapSize; ++i) {
        if (text == viewModeMap[i].name)
            return viewModeMap[i].type;
    }
    return Page::ViewModeInvalid;
}

void Page::setViewMode(ViewMode viewMode)
{
    if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
        return;

    m_viewMode = viewMode;

    if (!m_mainFrame)
        return;

    if (m_mainFrame->view())
        m_mainFrame->view()->forceLayout();

    if (m_mainFrame->document())
335
        m_mainFrame->document()->styleResolverChanged(RecalcStyleImmediately);
336
}
337
#endif // ENABLE(VIEW_MODE_CSS_MEDIA)
338

darin's avatar
darin committed
339 340
void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
{
ggaren's avatar
ggaren committed
341
    ASSERT(!m_mainFrame); // Should only be called during initialization
darin's avatar
darin committed
342 343 344
    m_mainFrame = mainFrame;
}

345 346 347 348 349 350 351 352 353 354
bool Page::openedByDOM() const
{
    return m_openedByDOM;
}

void Page::setOpenedByDOM()
{
    m_openedByDOM = true;
}

355
BackForwardList* Page::backForwardList() const
beidson's avatar
beidson committed
356
{
357
    return m_backForwardController->client();
beidson's avatar
beidson committed
358 359 360 361
}

bool Page::goBack()
{
362
    HistoryItem* item = backForward()->backItem();
beidson's avatar
beidson committed
363 364 365 366 367 368 369 370 371 372
    
    if (item) {
        goToItem(item, FrameLoadTypeBack);
        return true;
    }
    return false;
}

bool Page::goForward()
{
373
    HistoryItem* item = backForward()->forwardItem();
beidson's avatar
beidson committed
374 375 376 377 378 379 380 381
    
    if (item) {
        goToItem(item, FrameLoadTypeForward);
        return true;
    }
    return false;
}

382 383 384 385
bool Page::canGoBackOrForward(int distance) const
{
    if (distance == 0)
        return true;
386
    if (distance > 0 && distance <= backForward()->forwardCount())
387
        return true;
388
    if (distance < 0 && -distance <= backForward()->backCount())
389 390 391 392 393 394 395 396 397
        return true;
    return false;
}

void Page::goBackOrForward(int distance)
{
    if (distance == 0)
        return;

398
    HistoryItem* item = backForward()->itemAtIndex(distance);
399 400
    if (!item) {
        if (distance > 0) {
401 402
            if (int forwardCount = backForward()->forwardCount()) 
                item = backForward()->itemAtIndex(forwardCount);
403
        } else {
404 405
            if (int backCount = backForward()->backCount())
                item = backForward()->itemAtIndex(-backCount);
406 407 408
        }
    }

409 410 411 412
    if (!item)
        return;

    goToItem(item, FrameLoadTypeIndexedBackForward);
413 414
}

beidson's avatar
beidson committed
415 416
void Page::goToItem(HistoryItem* item, FrameLoadType type)
{
417 418 419
    // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
    // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
    RefPtr<HistoryItem> protector(item);
420

421 422 423
    if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
        m_mainFrame->loader()->stopAllLoaders();

424
    m_mainFrame->loader()->history()->goToItem(item, type);
beidson's avatar
beidson committed
425 426
}

427 428
int Page::getHistoryLength()
{
429
    return backForward()->backCount() + 1 + backForward()->forwardCount();
430 431
}

darin's avatar
darin committed
432 433
void Page::setGroupName(const String& name)
{
434 435
    if (m_group && !m_group->name().isEmpty()) {
        ASSERT(m_group != m_singlePageGroup.get());
darin@apple.com's avatar
darin@apple.com committed
436 437
        ASSERT(!m_singlePageGroup);
        m_group->removePage(this);
darin's avatar
darin committed
438
    }
439

darin@apple.com's avatar
darin@apple.com committed
440
    if (name.isEmpty())
441
        m_group = m_singlePageGroup.get();
darin@apple.com's avatar
darin@apple.com committed
442 443
    else {
        m_singlePageGroup.clear();
444 445
        m_group = PageGroup::pageGroup(name);
        m_group->addPage(this);
darin's avatar
darin committed
446 447 448
    }
}

449 450
const String& Page::groupName() const
{
451
    return m_group ? m_group->name() : nullAtom.string();
452 453
}

darin@apple.com's avatar
darin@apple.com committed
454
void Page::initGroup()
darin's avatar
darin committed
455
{
darin@apple.com's avatar
darin@apple.com committed
456 457
    ASSERT(!m_singlePageGroup);
    ASSERT(!m_group);
458
    m_singlePageGroup = PageGroup::create(this);
darin@apple.com's avatar
darin@apple.com committed
459
    m_group = m_singlePageGroup.get();
darin's avatar
darin committed
460 461
}

462
void Page::scheduleForcedStyleRecalcForAllPages()
darin's avatar
darin committed
463 464 465 466 467 468
{
    if (!allPages)
        return;
    HashSet<Page*>::iterator end = allPages->end();
    for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
469
            frame->document()->scheduleForcedStyleRecalc();
darin's avatar
darin committed
470 471
}

472 473 474
void Page::setNeedsRecalcStyleInAllFrames()
{
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
475
        frame->document()->styleResolverChanged(DeferRecalcStyle);
476 477
}

478 479 480 481 482 483 484 485 486 487 488
void Page::refreshPlugins(bool reload)
{
    if (!allPages)
        return;

    PluginData::refresh();

    Vector<RefPtr<Frame> > framesNeedingReload;

    HashSet<Page*>::iterator end = allPages->end();
    for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
489 490 491
        Page* page = *it;
        
        // Clear out the page's plug-in data.
492
        if (page->m_pluginData)
493
            page->m_pluginData = 0;
494

495 496 497 498
        if (!reload)
            continue;
        
        for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
499
            if (frame->loader()->subframeLoader()->containsPlugins())
500
                framesNeedingReload.append(frame);
501 502 503 504 505 506 507 508 509
        }
    }

    for (size_t i = 0; i < framesNeedingReload.size(); ++i)
        framesNeedingReload[i]->loader()->reload();
}

PluginData* Page::pluginData() const
{
510
    if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
511
        return 0;
512 513 514 515 516
    if (!m_pluginData)
        m_pluginData = PluginData::create(this);
    return m_pluginData.get();
}

517
inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
jhoneycutt@apple.com's avatar
jhoneycutt@apple.com committed
518
{
519 520 521 522 523
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
            return listener;
    }
    return 0;
524 525
}

526 527 528 529 530 531 532
void Page::setCanStartMedia(bool canStartMedia)
{
    if (m_canStartMedia == canStartMedia)
        return;

    m_canStartMedia = canStartMedia;

533
    while (m_canStartMedia) {
534 535
        MediaCanStartListener* listener = takeAnyMediaCanStartListener();
        if (!listener)
536 537 538
            break;
        listener->mediaCanStart();
    }
jhoneycutt@apple.com's avatar
jhoneycutt@apple.com committed
539 540
}

541 542 543 544 545 546 547 548
static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
{
    return forward
        ? curr->tree()->traverseNextWithWrap(wrapFlag)
        : curr->tree()->traversePreviousWithWrap(wrapFlag);
}

bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
549 550 551 552 553
{
    return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
}

bool Page::findString(const String& target, FindOptions options)
554 555 556 557
{
    if (target.isEmpty() || !mainFrame())
        return false;

558
    bool shouldWrap = options & WrapAround;
559 560 561
    Frame* frame = focusController()->focusedOrMainFrame();
    Frame* startFrame = frame;
    do {
562
        if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
563
            if (frame != startFrame)
darin@apple.com's avatar
darin@apple.com committed
564
                startFrame->selection()->clear();
565 566 567
            focusController()->setFocusedFrame(frame);
            return true;
        }
568
        frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
569 570 571 572
    } while (frame && frame != startFrame);

    // Search contents of startFrame, on the other side of the selection that we did earlier.
    // We cheat a bit and just research with wrap on
darin@apple.com's avatar
darin@apple.com committed
573
    if (shouldWrap && !startFrame->selection()->isNone()) {
574
        bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
575 576 577 578 579 580 581
        focusController()->setFocusedFrame(frame);
        return found;
    }

    return false;
}

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
void Page::findStringMatchingRanges(const String& target, FindOptions options, int limit, Vector<RefPtr<Range> >* matchRanges, int& indexForSelection)
{
    indexForSelection = 0;
    if (!mainFrame())
        return;

    Frame* frame = mainFrame();
    Frame* frameWithSelection = 0;
    do {
        frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matchRanges->size()) : 0, true, matchRanges);
        if (frame->selection()->isRange())
            frameWithSelection = frame;
        frame = incrementFrame(frame, true, false);
    } while (frame);

    if (matchRanges->isEmpty())
        return;

    if (frameWithSelection) {
        indexForSelection = NoMatchBeforeUserSelection;
        RefPtr<Range> selectedRange = frameWithSelection->selection()->selection().firstRange();
        for (size_t i = 0; i < matchRanges->size(); ++i) {
604
            if (selectedRange->compareBoundaryPoints(Range::START_TO_END, matchRanges->at(i).get(), IGNORE_EXCEPTION) < 0) {
605 606 607 608 609 610 611
                indexForSelection = i;
                break;
            }
        }
    }
}

612 613 614 615 616 617 618 619 620 621 622 623
PassRefPtr<Range> Page::rangeOfString(const String& target, Range* referenceRange, FindOptions options)
{
    if (target.isEmpty() || !mainFrame())
        return 0;

    if (referenceRange && referenceRange->ownerDocument()->page() != this)
        return 0;

    bool shouldWrap = options & WrapAround;
    Frame* frame = referenceRange ? referenceRange->ownerDocument()->frame() : mainFrame();
    Frame* startFrame = frame;
    do {
624
        if (RefPtr<Range> resultRange = frame->editor()->rangeOfString(target, frame == startFrame ? referenceRange : 0, options & ~WrapAround))
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
            return resultRange.release();

        frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
    } while (frame && frame != startFrame);

    // Search contents of startFrame, on the other side of the reference range that we did earlier.
    // We cheat a bit and just search again with wrap on.
    if (shouldWrap && referenceRange) {
        if (RefPtr<Range> resultRange = startFrame->editor()->rangeOfString(target, referenceRange, options | WrapAround | StartInSelection))
            return resultRange.release();
    }

    return 0;
}

alice.liu@apple.com's avatar
alice.liu@apple.com committed
640
unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
641 642 643 644 645
{
    return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
}

unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
646 647 648 649 650 651 652 653
{
    if (target.isEmpty() || !mainFrame())
        return 0;

    unsigned matches = 0;

    Frame* frame = mainFrame();
    do {
654
        frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
655
        matches += frame->editor()->countMatchesForText(target, 0, options, limit ? (limit - matches) : 0, true, 0);
656 657 658 659 660 661 662 663 664 665 666 667 668
        frame = incrementFrame(frame, true, false);
    } while (frame);

    return matches;
}

void Page::unmarkAllTextMatches()
{
    if (!mainFrame())
        return;

    Frame* frame = mainFrame();
    do {
669
        frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
670 671 672 673
        frame = incrementFrame(frame, true, false);
    } while (frame);
}

674
const VisibleSelection& Page::selection() const
adele's avatar
adele committed
675
{
darin@apple.com's avatar
darin@apple.com committed
676
    return focusController()->focusedOrMainFrame()->selection()->selection();
adele's avatar
adele committed
677 678
}

darin's avatar
darin committed
679 680
void Page::setDefersLoading(bool defers)
{
ap@apple.com's avatar
ap@apple.com committed
681 682 683
    if (!m_settings->loadDeferringEnabled())
        return;

684 685 686 687 688 689 690 691 692 693 694
    if (m_settings->wantsBalancedSetDefersLoadingBehavior()) {
        ASSERT(defers || m_defersLoadingCallCount);
        if (defers && ++m_defersLoadingCallCount > 1)
            return;
        if (!defers && --m_defersLoadingCallCount)
            return;
    } else {
        ASSERT(!m_defersLoadingCallCount);
        if (defers == m_defersLoading)
            return;
    }
darin's avatar
darin committed
695 696 697 698 699 700

    m_defersLoading = defers;
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
        frame->loader()->setDefersLoading(defers);
}

justing's avatar
justing committed
701 702 703 704 705
void Page::clearUndoRedoOperations()
{
    m_editorClient->clearUndoRedoOperations();
}

hyatt's avatar
hyatt committed
706 707 708 709 710 711 712 713 714 715
bool Page::inLowQualityImageInterpolationMode() const
{
    return m_inLowQualityInterpolationMode;
}

void Page::setInLowQualityImageInterpolationMode(bool mode)
{
    m_inLowQualityInterpolationMode = mode;
}

mitz@apple.com's avatar
mitz@apple.com committed
716 717 718 719 720 721 722 723 724 725
void Page::setMediaVolume(float volume)
{
    if (volume < 0 || volume > 1)
        return;

    if (m_mediaVolume == volume)
        return;

    m_mediaVolume = volume;
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
ap@webkit.org's avatar
ap@webkit.org committed
726
        frame->document()->mediaVolumeDidChange();
mitz@apple.com's avatar
mitz@apple.com committed
727 728 729
    }
}

730
void Page::setPageScaleFactor(float scale, const IntPoint& origin)
731 732
{
    Document* document = mainFrame()->document();
733 734 735
    FrameView* view = document->view();

    if (scale == m_pageScaleFactor) {
736
        if (view && (view->scrollPosition() != origin || view->delegatesScrolling())) {
737 738
            if (!m_settings->applyPageScaleFactorInCompositor())
                document->updateLayoutIgnorePendingStylesheets();
739 740 741 742
            view->setScrollPosition(origin);
        }
        return;
    }
743 744 745

    m_pageScaleFactor = scale;

746 747 748
    if (!m_settings->applyPageScaleFactorInCompositor()) {
        if (document->renderer())
            document->renderer()->setNeedsLayout(true);
749

750
        document->recalcStyle(Node::Force);
751

752 753 754
        // Transform change on RenderView doesn't trigger repaint on non-composited contents.
        mainFrame()->view()->invalidateRect(IntRect(LayoutRect::infiniteRect()));
    }
755

756 757 758 759
#if USE(ACCELERATED_COMPOSITING)
    mainFrame()->deviceOrPageScaleFactorChanged();
#endif

760 761 762
    if (view && view->fixedElementsLayoutRelativeToFrame())
        view->setViewportConstrainedObjectsNeedLayout();

763
    if (view && view->scrollPosition() != origin) {
764
        if (!m_settings->applyPageScaleFactorInCompositor() && document->renderer() && document->renderer()->needsLayout() && view->didFirstLayout())
765 766
            view->layout();
        view->setScrollPosition(origin);
767 768 769 770
    }
}


771 772 773 774 775 776 777 778 779
void Page::setDeviceScaleFactor(float scaleFactor)
{
    if (m_deviceScaleFactor == scaleFactor)
        return;

    m_deviceScaleFactor = scaleFactor;
    setNeedsRecalcStyleInAllFrames();

#if USE(ACCELERATED_COMPOSITING)
780 781
    if (mainFrame())
        mainFrame()->deviceOrPageScaleFactorChanged();
782
#endif
783

784 785 786
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
        frame->editor()->deviceScaleFactorChanged();

787
    pageCache()->markPagesForFullStyleRecalc(this);
788 789
}

790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
void Page::setShouldSuppressScrollbarAnimations(bool suppressAnimations)
{
    if (suppressAnimations == m_suppressScrollbarAnimations)
        return;

    if (!suppressAnimations) {
        // If animations are not going to be suppressed anymore, then there is nothing to do here but
        // change the cached value.
        m_suppressScrollbarAnimations = suppressAnimations;
        return;
    }

    // On the other hand, if we are going to start suppressing animations, then we need to make sure we
    // finish any current scroll animations first.
    FrameView* view = mainFrame()->view();
    if (!view)
        return;

    view->finishCurrentScrollAnimations();
    
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        FrameView* frameView = frame->view();
        if (!frameView)
            continue;

        const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
        if (!scrollableAreas)
            continue;

        for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
            ScrollableArea* scrollableArea = *it;
            ASSERT(scrollableArea->scrollbarsCanBeActive());

            scrollableArea->finishCurrentScrollAnimations();
        }
    }

    m_suppressScrollbarAnimations = suppressAnimations;
}

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
bool Page::rubberBandsAtBottom()
{
    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        return scrollingCoordinator->rubberBandsAtBottom();

    return false;
}

void Page::setRubberBandsAtBottom(bool rubberBandsAtBottom)
{
    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        scrollingCoordinator->setRubberBandsAtBottom(rubberBandsAtBottom);
}

bool Page::rubberBandsAtTop()
{
    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        return scrollingCoordinator->rubberBandsAtTop();

    return false;
}

void Page::setRubberBandsAtTop(bool rubberBandsAtTop)
{
    if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
        scrollingCoordinator->setRubberBandsAtTop(rubberBandsAtTop);
}

858 859
void Page::setPagination(const Pagination& pagination)
{
860
    if (m_pagination == pagination)
861 862 863 864 865
        return;

    m_pagination = pagination;

    setNeedsRecalcStyleInAllFrames();
866
    pageCache()->markPagesForFullStyleRecalc(this);
867 868
}

869 870 871 872 873 874
unsigned Page::pageCount() const
{
    if (m_pagination.mode == Pagination::Unpaginated)
        return 0;

    FrameView* frameView = mainFrame()->view();
875 876
    if (frameView->needsLayout())
        frameView->layout();
877 878

    RenderView* contentRenderer = mainFrame()->contentRenderer();
879
    return contentRenderer ? contentRenderer->columnCount(contentRenderer->columnInfo()) : 0;
880 881
}

882 883
void Page::didMoveOnscreen()
{
884 885
    m_isOnscreen = true;

886
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
887 888
        if (FrameView* frameView = frame->view())
            frameView->didMoveOnscreen();
889
    }
890 891
    
    resumeScriptedAnimations();
892 893 894 895
}

void Page::willMoveOffscreen()
{
896 897
    m_isOnscreen = false;

898
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
899 900
        if (FrameView* frameView = frame->view())
            frameView->willMoveOffscreen();
901
    }
902 903
    
    suspendScriptedAnimations();
904 905
}

906 907 908 909 910 911 912 913 914 915 916 917 918
void Page::setIsInWindow(bool isInWindow)
{
    if (m_isInWindow == isInWindow)
        return;

    m_isInWindow = isInWindow;

    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        if (FrameView* frameView = frame->view())
            frameView->setIsInWindow(isInWindow);
    }
}

919 920 921 922 923 924 925 926 927 928
void Page::windowScreenDidChange(PlatformDisplayID displayID)
{
    m_displayID = displayID;
    
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        if (frame->document())
            frame->document()->windowScreenDidChange(displayID);
    }
}

929 930
void Page::suspendScriptedAnimations()
{
931
    m_scriptedAnimationsSuspended = true;
932 933 934 935 936 937 938 939
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        if (frame->document())
            frame->document()->suspendScriptedAnimationControllerCallbacks();
    }
}

void Page::resumeScriptedAnimations()
{
940
    m_scriptedAnimationsSuspended = false;
941 942 943 944 945 946
    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
        if (frame->document())
            frame->document()->resumeScriptedAnimationControllerCallbacks();
    }
}

947 948
void Page::userStyleSheetLocationChanged()
{
949 950 951
    // FIXME: Eventually we will move to a model of just being handed the sheet
    // text instead of loading the URL ourselves.
    KURL url = m_settings->userStyleSheetLocation();
952 953 954
    
    // Allow any local file URL scheme to be loaded.
    if (SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()))
955
        m_userStyleSheetPath = url.fileSystemPath();
956 957 958 959 960 961
    else
        m_userStyleSheetPath = String();

    m_didLoadUserStyleSheet = false;
    m_userStyleSheet = String();
    m_userStyleSheetModificationTime = 0;