FrameView.cpp 45.3 KB
Newer Older
kocienda's avatar
kocienda committed
1
2
3
4
5
6
/* 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 Dirk Mueller <mueller@kde.org>
7
 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
kocienda's avatar
kocienda committed
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * 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.
 */
darin's avatar
darin committed
24

mjs's avatar
mjs committed
25
#include "config.h"
mjs's avatar
mjs committed
26
#include "FrameView.h"
darin's avatar
darin committed
27

28
#include "AXObjectCache.h"
darin's avatar
darin committed
29
#include "CachedImage.h"
darin's avatar
darin committed
30
#include "Cursor.h"
darin's avatar
darin committed
31
#include "EventNames.h"
mjs's avatar
mjs committed
32
#include "Frame.h"
thatcher's avatar
thatcher committed
33
#include "FrameTree.h"
weinig's avatar
   
weinig committed
34
#include "HTMLDocument.h"
35
#include "HTMLFrameSetElement.h"
darin's avatar
darin committed
36
#include "HTMLInputElement.h"
weinig's avatar
   
weinig committed
37
#include "HTMLNames.h"
darin's avatar
darin committed
38
#include "Image.h"
weinig's avatar
   
weinig committed
39
#include "MouseEvent.h"
darin's avatar
darin committed
40
#include "MouseEventWithHitTestResults.h"
andersca's avatar
andersca committed
41
#include "OverflowEvent.h"
weinig's avatar
   
weinig committed
42
#include "PlatformKeyboardEvent.h"
43
#include "PlatformScrollBar.h"
weinig's avatar
   
weinig committed
44
45
#include "PlatformWheelEvent.h"
#include "RenderArena.h"
46
#include "RenderPart.h"
eseidel's avatar
eseidel committed
47
#include "RenderText.h"
weinig's avatar
   
weinig committed
48
#include "RenderView.h"
darin's avatar
darin committed
49
50
#include "SelectionController.h"
#include "cssstyleselector.h"
eseidel's avatar
eseidel committed
51

52
#ifdef SVG_SUPPORT
rwlbuis's avatar
rwlbuis committed
53
54
55
56
57
58
#include "XLinkNames.h"
#include "SVGNames.h"
#include "SVGCursorElement.h"
#include "SVGLength.h"
#endif

darin's avatar
darin committed
59
60
namespace WebCore {

darin's avatar
darin committed
61
using namespace EventNames;
62
using namespace HTMLNames;
63
#ifdef SVG_SUPPORT
rwlbuis's avatar
rwlbuis committed
64
65
using namespace SVGNames;
#endif
darin's avatar
darin committed
66

andersca's avatar
andersca committed
67
68
69
70
71
72
struct ScheduledEvent {
    RefPtr<Event> m_event;
    RefPtr<EventTargetNode> m_eventTarget;
    bool m_tempEvent;
};

73
class FrameViewPrivate {
kocienda's avatar
kocienda committed
74
public:
darin's avatar
darin committed
75
    FrameViewPrivate(FrameView* view)
darin's avatar
darin committed
76
77
78
        : m_hasBorder(false)
        , layoutTimer(view, &FrameView::layoutTimerFired)
        , hoverTimer(view, &FrameView::hoverTimerFired)
adele's avatar
adele committed
79
        , m_resizeLayer(0)
80
        , m_mediaType("screen")
andersca's avatar
andersca committed
81
82
83
        , m_scheduledEvents(0)
        , m_overflowStatusDirty(true)
        , m_viewportRenderer(0)
kocienda's avatar
kocienda committed
84
    {
85
        repaintRects = 0;
darin's avatar
darin committed
86
        isTransparent = false;
thatcher's avatar
thatcher committed
87
        baseBackgroundColor = Color::white;
darin's avatar
darin committed
88
        vmode = hmode = ScrollBarAuto;
89
        needToInitScrollBars = true;
darin's avatar
darin committed
90
        reset();
kocienda's avatar
kocienda committed
91
    }
92
    ~FrameViewPrivate()
kocienda's avatar
kocienda committed
93
    {
94
        delete repaintRects;
darin's avatar
darin committed
95
        delete m_scheduledEvents;
kocienda's avatar
kocienda committed
96
97
98
    }
    void reset()
    {
99
        underMouse = 0;
ap's avatar
ap committed
100
101
        oldUnder = 0;
        oldSubframe = 0;
102
        oldScrollBar = 0;
kocienda's avatar
kocienda committed
103
104
        linkPressed = false;
        useSlowRepaints = false;
105
        slowRepaintObjectCount = 0;
mjs's avatar
mjs committed
106
        dragTarget = 0;
107
        borderTouched = false;
108
109
        scrollBarMoved = false;
        ignoreWheelEvents = false;
110
111
112
        borderX = 30;
        borderY = 30;
        clickCount = 0;
darin's avatar
darin committed
113
        clickNode = 0;
114
        scrollingSelf = false;
darin's avatar
darin committed
115
        layoutTimer.stop();
adele's avatar
adele committed
116
        layoutRoot = 0;
117
        delayedLayout = false;
118
        mousePressed = false;
119
        doFullRepaint = true;
120
        layoutSchedulingEnabled = true;
121
        layoutCount = 0;
122
        firstLayout = true;
adele's avatar
adele committed
123
        hoverTimer.stop();
124
125
        if (repaintRects)
            repaintRects->clear();
ap's avatar
ap committed
126
        resizingFrameSet = 0;
adele's avatar
adele committed
127
        m_resizeLayer = 0;
kocienda's avatar
kocienda committed
128
129
    }

darin's avatar
darin committed
130
    RefPtr<Node> underMouse;
ap's avatar
ap committed
131
132
    RefPtr<Node> oldUnder;
    RefPtr<Frame> oldSubframe;
133
    RefPtr<PlatformScrollBar> oldScrollBar;
kocienda's avatar
kocienda committed
134

darin's avatar
darin committed
135
136
137
138
139
    bool borderTouched : 1;
    bool borderStart : 1;
    bool scrollBarMoved : 1;
    bool doFullRepaint : 1;
    bool m_hasBorder : 1;
140
    
darin's avatar
darin committed
141
142
    ScrollBarMode vmode;
    ScrollBarMode hmode;
kocienda's avatar
kocienda committed
143
144
    bool linkPressed;
    bool useSlowRepaints;
145
    unsigned slowRepaintObjectCount;
146
    bool ignoreWheelEvents;
kocienda's avatar
kocienda committed
147
148

    int borderX, borderY;
darin's avatar
darin committed
149
    int clickCount;
darin's avatar
darin committed
150
    RefPtr<Node> clickNode;
kocienda's avatar
kocienda committed
151

152
    bool scrollingSelf;
darin's avatar
darin committed
153
    Timer<FrameView> layoutTimer;
154
    bool delayedLayout;
adele's avatar
adele committed
155
    RefPtr<Node> layoutRoot;
hyatt's avatar
hyatt committed
156
    
157
    bool layoutSchedulingEnabled;
158
159
    int layoutCount;

160
161
    bool firstLayout;
    bool needToInitScrollBars;
162
    bool mousePressed;
darin's avatar
darin committed
163
    bool isTransparent;
thatcher's avatar
thatcher committed
164
165
    Color baseBackgroundColor;

adele's avatar
adele committed
166
167
    Timer<FrameView> hoverTimer;
    
adele's avatar
adele committed
168
    RenderLayer* m_resizeLayer;
169
    IntSize offsetFromResizeCorner;
adele's avatar
adele committed
170
    
171
172
    // Used by objects during layout to communicate repaints that need to take place only
    // after all layout has been completed.
darin's avatar
darin committed
173
    DeprecatedPtrList<RenderObject::RepaintInfo>* repaintRects;
trey's avatar
trey committed
174
    
darin's avatar
darin committed
175
176
    RefPtr<Node> dragTarget;
    RefPtr<HTMLFrameSetElement> resizingFrameSet;
177
178
    
    String m_mediaType;
andersca's avatar
andersca committed
179
180
181
182
183
184
185
    
    Vector<ScheduledEvent*>* m_scheduledEvents;
    
    bool m_overflowStatusDirty;
    bool horizontalOverflow;
    bool m_verticalOverflow;    
    RenderObject* m_viewportRenderer;
kocienda's avatar
kocienda committed
186
187
};

darin's avatar
darin committed
188
FrameView::FrameView(Frame *frame)
189
    : m_refCount(1)
darin's avatar
darin committed
190
191
    , m_frame(frame)
    , d(new FrameViewPrivate(this))
kocienda's avatar
kocienda committed
192
193
194
{
    init();

darin's avatar
darin committed
195
    show();
kocienda's avatar
kocienda committed
196
197
}

198
FrameView::~FrameView()
kocienda's avatar
kocienda committed
199
{
200
201
    resetScrollBars();

202
    ASSERT(m_refCount == 0);
mjs's avatar
mjs committed
203

adele's avatar
adele committed
204
205
    if (d->hoverTimer.isActive())
        d->hoverTimer.stop();
darin's avatar
darin committed
206
207
    if (m_frame) {
        // FIXME: Is this really the right place to call detach on the document?
darin's avatar
darin committed
208
        if (Document* doc = m_frame->document())
darin's avatar
darin committed
209
            doc->detach();
darin's avatar
darin committed
210
        if (RenderPart* renderer = m_frame->ownerRenderer())
darin's avatar
darin committed
211
            renderer->setWidget(0);
212
    }
213

darin's avatar
darin committed
214
215
    delete d;
    d = 0;
kocienda's avatar
kocienda committed
216
217
}

ggaren's avatar
ggaren committed
218
219
220
221
222
bool FrameView::isFrameView() const 
{ 
    return true; 
}

223
void FrameView::clearPart()
rjw's avatar
rjw committed
224
{
darin's avatar
darin committed
225
    m_frame = 0;
rjw's avatar
rjw committed
226
227
}

228
void FrameView::resetScrollBars()
229
230
{
    // Reset the document's scrollbars back to our defaults before we yield the floor.
231
    d->firstLayout = true;
232
    suppressScrollBars(true);
darin's avatar
darin committed
233
234
    ScrollView::setVScrollBarMode(d->vmode);
    ScrollView::setHScrollBarMode(d->hmode);
235
236
237
    suppressScrollBars(false);
}

238
void FrameView::init()
kocienda's avatar
kocienda committed
239
{
240
241
    m_margins = IntSize(-1, -1); // undefined
    m_size = IntSize();
kocienda's avatar
kocienda committed
242
243
}

244
void FrameView::clear()
kocienda's avatar
kocienda committed
245
{
246
    setStaticBackground(false);
kocienda's avatar
kocienda committed
247
    
justing's avatar
justing committed
248
    m_frame->selectionController()->clear();
kocienda's avatar
kocienda committed
249
250

    d->reset();
251

weinig's avatar
weinig committed
252
#ifdef INSTRUMENT_LAYOUT_SCHEDULING
darin's avatar
darin committed
253
    if (d->layoutTimer.isActive() && m_frame->document() && !m_frame->document()->ownerElement())
254
        printf("Killing the layout timer from a clear at %d\n", m_frame->document()->elapsedTime());
darin's avatar
darin committed
255
256
257
#endif    
    d->layoutTimer.stop();

darin's avatar
darin committed
258
    cleared();
kocienda's avatar
kocienda committed
259

260
    suppressScrollBars(true);
kocienda's avatar
kocienda committed
261
262
}

263
void FrameView::initScrollBars()
264
265
266
267
268
269
{
    if (!d->needToInitScrollBars)
        return;
    d->needToInitScrollBars = false;
    setScrollBarsMode(hScrollBarMode());
}
270

271
void FrameView::setMarginWidth(int w)
272
273
{
    // make it update the rendering area when set
274
    m_margins.setWidth(w);
275
276
}

277
void FrameView::setMarginHeight(int h)
278
279
{
    // make it update the rendering area when set
280
    m_margins.setHeight(h);
kocienda's avatar
kocienda committed
281
282
}

283
void FrameView::adjustViewSize()
rjw's avatar
WebKit:    
rjw committed
284
{
darin's avatar
darin committed
285
    if (m_frame->document()) {
darin's avatar
darin committed
286
        Document *document = m_frame->document();
rjw's avatar
WebKit:    
rjw committed
287

288
        RenderView* root = static_cast<RenderView *>(document->renderer());
289
        if (!root)
rjw's avatar
WebKit:    
rjw committed
290
291
292
293
294
295
296
297
298
            return;
        
        int docw = root->docWidth();
        int doch = root->docHeight();
    
        resizeContents(docw, doch);
    }
}

299
void FrameView::applyOverflowToViewport(RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
300
{
301
    // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
302
    // overflow:hidden and overflow:scroll on <body> as applying to the document's
303
304
    // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
    // use the root element.
305
    switch (o->style()->overflowX()) {
306
        case OHIDDEN:
307
            hMode = ScrollBarAlwaysOff;
308
309
            break;
        case OSCROLL:
310
            hMode = ScrollBarAlwaysOn;
311
312
            break;
        case OAUTO:
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
            hMode = ScrollBarAuto;
            break;
        default:
            // Don't set it at all.
            ;
    }
    
     switch (o->style()->overflowY()) {
        case OHIDDEN:
            vMode = ScrollBarAlwaysOff;
            break;
        case OSCROLL:
            vMode = ScrollBarAlwaysOn;
            break;
        case OAUTO:
            vMode = ScrollBarAuto;
329
330
331
332
333
            break;
        default:
            // Don't set it at all.
            ;
    }
andersca's avatar
andersca committed
334
335

    d->m_viewportRenderer = o;
336
337
}

338
int FrameView::layoutCount() const
339
340
341
342
{
    return d->layoutCount;
}

343
bool FrameView::needsFullRepaint() const
344
345
346
347
{
    return d->doFullRepaint;
}

348
void FrameView::addRepaintInfo(RenderObject* o, const IntRect& r)
349
350
{
    if (!d->repaintRects) {
darin's avatar
darin committed
351
        d->repaintRects = new DeprecatedPtrList<RenderObject::RepaintInfo>;
352
353
354
355
356
357
        d->repaintRects->setAutoDelete(true);
    }
    
    d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
}

ap's avatar
ap committed
358
359
360
361
362
Node* FrameView::layoutRoot() const
{
    return layoutPending() ? 0 : d->layoutRoot.get();
}

adele's avatar
adele committed
363
void FrameView::layout(bool allowSubtree)
kocienda's avatar
kocienda committed
364
{
darin's avatar
darin committed
365
    d->layoutTimer.stop();
366
    d->delayedLayout = false;
367

adele's avatar
adele committed
368
369
370
    // Protect the view from being deleted during layout (in recalcStyle)
    RefPtr<FrameView> protector(this);

mjs's avatar
mjs committed
371
    if (!m_frame) {
372
373
374
        // FIXME: Do we need to set m_size.width here?
        // FIXME: Should we set m_size.height here too?
        m_size.setWidth(visibleWidth());
darin's avatar
darin committed
375
376
377
        return;
    }

adele's avatar
adele committed
378
379
380
381
382
383
384
    if (!allowSubtree && d->layoutRoot) {
        if (d->layoutRoot->renderer())
            d->layoutRoot->renderer()->markContainingBlocksForLayout(false);
        d->layoutRoot = 0;
    }

    bool subtree = d->layoutRoot;
darin's avatar
darin committed
385
    Document* document = m_frame->document();
386
    if (!document) {
387
388
        // FIXME: Should we set m_size.height here too?
        m_size.setWidth(visibleWidth());
389
390
        return;
    }
kocienda's avatar
kocienda committed
391

adele's avatar
adele committed
392
    Node* rootNode = subtree ? d->layoutRoot.get() : document;
justing's avatar
justing committed
393
394
    d->layoutSchedulingEnabled = false;

395
396
397
398
    // Always ensure our style info is up-to-date.  This can happen in situations where
    // the layout beats any sort of style recalc update that needs to occur.
    if (document->hasChangedChild())
        document->recalcStyle();
adele's avatar
adele committed
399
400
401
402
403
    
    // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 
    // so there's no point to continuiing to layout
    if (protector->hasOneRef())
        return;
404

adele's avatar
adele committed
405
    RenderObject* root = rootNode->renderer();
darin's avatar
darin committed
406
    if (!root) {
407
        // FIXME: Do we need to set m_size here?
justing's avatar
justing committed
408
        d->layoutSchedulingEnabled = true;
409
        return;
darin's avatar
darin committed
410
    }
kocienda's avatar
kocienda committed
411

412
413
414
    ScrollBarMode hMode = d->hmode;
    ScrollBarMode vMode = d->vmode;
    
adele's avatar
adele committed
415
416
417
418
419
420
421
422
423
424
425
    if (!subtree) {
        Document* document = static_cast<Document*>(rootNode);
        RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
        if (document->isHTMLDocument()) {
            Node *body = static_cast<HTMLDocument*>(document)->body();
            if (body && body->renderer()) {
                if (body->hasTagName(framesetTag)) {
                    body->renderer()->setNeedsLayout(true);
                    vMode = ScrollBarAlwaysOff;
                    hMode = ScrollBarAlwaysOff;
                } else if (body->hasTagName(bodyTag)) {
ddkilzer's avatar
ddkilzer committed
426
427
                    if (!d->firstLayout && m_size.height() != visibleHeight() && static_cast<RenderBox*>(body->renderer())->stretchesToViewHeight())
                        body->renderer()->setChildNeedsLayout(true);
428
429
                    // It's sufficient to just check one overflow direction, since it's illegal to have visible in only one direction.
                    RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE ? body->renderer() : rootRenderer;
adele's avatar
adele committed
430
431
                    applyOverflowToViewport(o, hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
                }
432
            }
adele's avatar
adele committed
433
434
        } else if (rootRenderer)
            applyOverflowToViewport(rootRenderer, hMode, vMode); // XML/XHTML UAs use the root element.
weinig's avatar
weinig committed
435
#ifdef INSTRUMENT_LAYOUT_SCHEDULING
adele's avatar
adele committed
436
437
        if (d->firstLayout && !document->ownerElement())
            printf("Elapsed time before first layout: %d\n", document->elapsedTime());
hyatt's avatar
hyatt committed
438
#endif
adele's avatar
adele committed
439
    }
hyatt's avatar
hyatt committed
440

adele's avatar
adele committed
441
    d->doFullRepaint = !subtree && (d->firstLayout || static_cast<RenderView*>(root)->printingMode());
442
443
    if (d->repaintRects)
        d->repaintRects->clear();
444

cblu's avatar
cblu committed
445
    bool didFirstLayout = false;
adele's avatar
adele committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    if (!subtree) {
        // Now set our scrollbar state for the layout.
        ScrollBarMode currentHMode = hScrollBarMode();
        ScrollBarMode currentVMode = vScrollBarMode();

        if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
            suppressScrollBars(true);
            if (d->firstLayout) {
                d->firstLayout = false;
                didFirstLayout = true;
                
                // Set the initial vMode to AlwaysOn if we're auto.
                if (vMode == ScrollBarAuto)
                    ScrollView::setVScrollBarMode(ScrollBarAlwaysOn); // This causes a vertical scrollbar to appear.
                // Set the initial hMode to AlwaysOff if we're auto.
                if (hMode == ScrollBarAuto)
                    ScrollView::setHScrollBarMode(ScrollBarAlwaysOff); // This causes a horizontal scrollbar to disappear.
            }
464
            
adele's avatar
adele committed
465
466
467
468
469
470
            if (hMode == vMode)
                ScrollView::setScrollBarsMode(hMode);
            else {
                ScrollView::setHScrollBarMode(hMode);
                ScrollView::setVScrollBarMode(vMode);
            }
471

adele's avatar
adele committed
472
473
            suppressScrollBars(false, true);
        }
474

adele's avatar
adele committed
475
        IntSize oldSize = m_size;
476

adele's avatar
adele committed
477
        m_size = IntSize(visibleWidth(), visibleHeight());
478

adele's avatar
adele committed
479
480
481
        if (oldSize != m_size)
            d->doFullRepaint = true;
    }
482
    
adele's avatar
adele committed
483
    RenderLayer* layer = root->enclosingLayer();
484
485
     
    if (!d->doFullRepaint) {
ddkilzer's avatar
ddkilzer committed
486
        layer->checkForRepaintOnResize();
487
488
489
        root->repaintObjectsBeforeLayout();
    }

adele's avatar
adele committed
490
491
492
493
    if (subtree) {
        if (root->recalcMinMax())
            root->recalcMinMaxWidths();
    }
494
    root->layout();
adele's avatar
adele committed
495
    d->layoutRoot = 0;
496

mjs's avatar
mjs committed
497
    m_frame->invalidateSelection();
498
   
499
500
    d->layoutSchedulingEnabled=true;

adele's avatar
adele committed
501
    if (!subtree && !static_cast<RenderView*>(root)->printingMode())
502
        resizeContents(layer->width(), layer->height());
503
504

    // Now update the positions of all layers.
505
    layer->updateLayerPositions(d->doFullRepaint);
506

507
    // We update our widget positions right after doing a layout.
adele's avatar
adele committed
508
509
    if (!subtree)
        static_cast<RenderView*>(root)->updateWidgetPositions();
510
    
511
512
513
514
    if (d->repaintRects && !d->repaintRects->isEmpty()) {
        // FIXME: Could optimize this and have objects removed from this list
        // if they ever do full repaints.
        RenderObject::RepaintInfo* r;
darin's avatar
darin committed
515
        DeprecatedPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
516
        for (; (r = it.current()); ++it)
517
518
519
520
            r->m_object->repaintRectangle(r->m_repaintRect);
        d->repaintRects->clear();
    }
    
521
    d->layoutCount++;
darin's avatar
darin committed
522

523
#if __APPLE__
524
    if (AXObjectCache::accessibilityEnabled())
harrison's avatar
harrison committed
525
        root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
526
    updateDashboardRegions();
527
#endif
rjw's avatar
rjw committed
528

529
530
531
    if (didFirstLayout)
        m_frame->didFirstLayout();
    
532
    if (root->needsLayout()) {
533
534
535
        scheduleRelayout();
        return;
    }
536
    setStaticBackground(useSlowRepaints());
cblu's avatar
cblu committed
537

538
539
540
    if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
        updateOverflowStatus(visibleWidth() < contentsWidth(),
                             visibleHeight() < contentsHeight());
andersca's avatar
andersca committed
541
542
543

    // Dispatch events scheduled during layout
    dispatchScheduledEvents();    
kocienda's avatar
kocienda committed
544
545
546
547
548
549
550
}

//
// Event Handling
//
/////////////////

ap's avatar
ap committed
551
552
static Frame* subframeForEvent(const MouseEventWithHitTestResults& mev)
{
darin's avatar
darin committed
553
    if (!mev.targetNode())
ap's avatar
ap committed
554
555
        return 0;

darin's avatar
darin committed
556
    RenderObject* renderer = mev.targetNode()->renderer();
ap's avatar
ap committed
557
558
559
560
561
562
563
564
565
566
    if (!renderer || !renderer->isWidget())
        return 0;

    Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
    if (!widget || !widget->isFrameView())
        return 0;

    return static_cast<FrameView*>(widget)->frame();
}

darin's avatar
darin committed
567
void FrameView::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
kocienda's avatar
kocienda committed
568
{
darin's avatar
darin committed
569
570
    if (!m_frame->document())
        return;
kocienda's avatar
kocienda committed
571

572
    RefPtr<FrameView> protector(this);
darin's avatar
darin committed
573

574
    d->mousePressed = true;
kocienda's avatar
kocienda committed
575

ap's avatar
ap committed
576
    MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
kocienda's avatar
kocienda committed
577

578
    if (m_frame->passSubframeEventToSubframe(mev)) {
darin's avatar
darin committed
579
        invalidateClick();
darin's avatar
darin committed
580
        return;
darin's avatar
darin committed
581
    }
darin's avatar
darin committed
582

darin's avatar
darin committed
583
    d->clickCount = mouseEvent.clickCount();
darin's avatar
darin committed
584
    d->clickNode = mev.targetNode();
adele's avatar
adele committed
585
586
587
588
589
590
    
    RenderLayer* layer = d->clickNode->renderer()? d->clickNode->renderer()->enclosingLayer() : 0;
    IntPoint p =  viewportToContents(mouseEvent.pos());
    if (layer && layer->isPointInResizeControl(p)) {
        layer->setInResizeMode(true);
        d->m_resizeLayer = layer;
591
        d->offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
adele's avatar
adele committed
592
593
594
        invalidateClick();
        return;  
    }
kocienda's avatar
kocienda committed
595

darin's avatar
darin committed
596
    bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
kocienda's avatar
kocienda committed
597

598
    if (!swallowEvent) {
andersca's avatar
andersca committed
599
600
601
602
603
604
605
        // Refetch the event target node if it currently is the shadow node inside an <input> element.
        // If a mouse event handler changes the input element type to one that has a widget associated,
        // we'd like to Frame::handleMousePressEvent to pass the event to the widget and thus the
        // event target node can't still be the shadow node.
        if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
            mev = prepareMouseEvent(true, true, false, mouseEvent);

darin's avatar
darin committed
606
        m_frame->handleMousePressEvent(mev);
607
608
609
610
611
        // Many AK widgets run their own event loops and consume events while the mouse is down.
        // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
        // the khtml state with this mouseUp, which khtml never saw.
        // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
        // is a hole here if the widget consumes the mouseUp and subsequent events.
mjs's avatar
mjs committed
612
        if (m_frame->lastEventIsMouseUp())
613
            d->mousePressed = false;
614
    }
kocienda's avatar
kocienda committed
615
616
}

darin's avatar
darin committed
617
void FrameView::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
kocienda's avatar
kocienda committed
618
{
darin's avatar
darin committed
619
620
    if (!m_frame->document())
        return;
kocienda's avatar
kocienda committed
621

622
    RefPtr<FrameView> protector(this);
darin's avatar
darin committed
623

trey's avatar
trey committed
624
625
    // We get this instead of a second mouse-up 
    d->mousePressed = false;
kocienda's avatar
kocienda committed
626

ap's avatar
ap committed
627
    MouseEventWithHitTestResults mev = prepareMouseEvent(false, true, false, mouseEvent);
kocienda's avatar
kocienda committed
628

629
    if (m_frame->passSubframeEventToSubframe(mev))
darin's avatar
darin committed
630
631
        return;

darin's avatar
darin committed
632
    d->clickCount = mouseEvent.clickCount();
darin's avatar
darin committed
633
    bool swallowEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, d->clickCount, mouseEvent, false);
darin's avatar
darin committed
634

darin's avatar
darin committed
635
636
    if (mev.targetNode() == d->clickNode)
        dispatchMouseEvent(clickEvent, mev.targetNode(), true, d->clickCount, mouseEvent, true);
637

rjw's avatar
rjw committed
638
    // Qt delivers a release event AND a double click event.
639
    if (!swallowEvent) {
darin's avatar
darin committed
640
641
        m_frame->handleMouseReleaseEvent(mev);
        m_frame->handleMouseReleaseDoubleClickEvent(mev);
642
    }
darin's avatar
darin committed
643
644

    invalidateClick();
kocienda's avatar
kocienda committed
645
646
}

darin's avatar
darin committed
647
static bool isSubmitImage(Node *node)
648
{
darin's avatar
darin committed
649
    return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->inputType() == HTMLInputElement::IMAGE;
650
651
}

darin's avatar
darin committed
652
static Cursor selectCursor(const MouseEventWithHitTestResults& event, Frame* frame, bool mousePressed)
darin's avatar
darin committed
653
{
darin's avatar
darin committed
654
    // During selection, use an I-beam no matter what we're over.
mjs's avatar
mjs committed
655
    if (mousePressed && frame->hasSelection())
darin's avatar
darin committed
656
        return iBeamCursor();
darin's avatar
darin committed
657

darin's avatar
darin committed
658
    Node* node = event.targetNode();
darin's avatar
darin committed
659
660
    RenderObject* renderer = node ? node->renderer() : 0;
    RenderStyle* style = renderer ? renderer->style() : 0;
darin's avatar
darin committed
661

rwlbuis's avatar
rwlbuis committed
662
663
664
665
666
    if (style && style->cursors()) {
        const CursorList* cursors = style->cursors();
        for (unsigned i = 0; i < cursors->size(); ++i) {
            CachedImage* cimage = (*cursors)[i].cursorImage;
            IntPoint hotSpot = (*cursors)[i].hotSpot;
667
#ifdef SVG_SUPPORT
rwlbuis's avatar
rwlbuis committed
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
            if (!cimage) {
                Element* e = node->document()->getElementById((*cursors)[i].cursorFragmentId);
                if (e && e->hasTagName(cursorTag)) {
                    hotSpot.setX(int(static_cast<SVGCursorElement*>(e)->x()->value()));
                    hotSpot.setY(int(static_cast<SVGCursorElement*>(e)->y()->value()));
                    cimage = static_cast<SVGCursorElement*>(e)->cachedImage();
                }
            }
#endif
            if (!cimage)
                continue;
            if (cimage->image()->isNull())
                break;
            if (!cimage->isErrorImage()) {
                return Cursor(cimage->image(), hotSpot);
}
        }
    }
darin's avatar
darin committed
686
687

    switch (style ? style->cursor() : CURSOR_AUTO) {
thatcher's avatar
thatcher committed
688
689
690
        case CURSOR_AUTO: {
            bool editable = (node && node->isContentEditable());
            if ((event.isOverLink() || isSubmitImage(node)) && (!editable || event.event().shiftKey()))
darin's avatar
darin committed
691
                return handCursor();
adele's avatar
adele committed
692
693
694
695
            RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0;
            bool inResizer = false;
            if (frame->view() && layer && layer->isPointInResizeControl(frame->view()->viewportToContents(event.event().pos())))
                inResizer = true;
696
            if ((editable || (renderer && renderer->isText() && renderer->canSelect())) && !inResizer && !RenderLayer::gScrollBar)
darin's avatar
darin committed
697
                return iBeamCursor();
adele's avatar
adele committed
698
            // FIXME: If the point is in a layer's overflow scrollbars, we should use the pointer cursor
darin's avatar
darin committed
699
            return pointerCursor();
thatcher's avatar
thatcher committed
700
        }
darin's avatar
darin committed
701
        case CURSOR_CROSS:
darin's avatar
darin committed
702
            return crossCursor();
darin's avatar
darin committed
703
        case CURSOR_POINTER:
darin's avatar
darin committed
704
            return handCursor();
darin's avatar
darin committed
705
        case CURSOR_MOVE:
darin's avatar
darin committed
706
            return moveCursor();
darin's avatar
darin committed
707
        case CURSOR_E_RESIZE:
darin's avatar
darin committed
708
            return eastResizeCursor();
darin's avatar
darin committed
709
        case CURSOR_W_RESIZE:
darin's avatar
darin committed
710
            return westResizeCursor();
darin's avatar
darin committed
711
        case CURSOR_N_RESIZE:
darin's avatar
darin committed
712
            return northResizeCursor();
darin's avatar
darin committed
713
        case CURSOR_S_RESIZE:
darin's avatar
darin committed
714
            return southResizeCursor();
darin's avatar
darin committed
715
        case CURSOR_NE_RESIZE:
darin's avatar
darin committed
716
            return northEastResizeCursor();
darin's avatar
darin committed
717
        case CURSOR_SW_RESIZE:
darin's avatar
darin committed
718
            return southWestResizeCursor();
darin's avatar
darin committed
719
        case CURSOR_NW_RESIZE:
darin's avatar
darin committed
720
            return northWestResizeCursor();
darin's avatar
darin committed
721
        case CURSOR_SE_RESIZE:
darin's avatar
darin committed
722
            return southEastResizeCursor();
thatcher's avatar
thatcher committed
723
724
725
726
727
728
729
730
731
732
733
734
        case CURSOR_NS_RESIZE:
            return northSouthResizeCursor();
        case CURSOR_EW_RESIZE:
            return eastWestResizeCursor();
        case CURSOR_NESW_RESIZE:
            return northEastSouthWestResizeCursor();
        case CURSOR_NWSE_RESIZE:
            return northWestSouthEastResizeCursor();
        case CURSOR_COL_RESIZE:
            return columnResizeCursor();
        case CURSOR_ROW_RESIZE:
            return rowResizeCursor();
darin's avatar
darin committed
735
        case CURSOR_TEXT:
darin's avatar
darin committed
736
            return iBeamCursor();
darin's avatar
darin committed
737
        case CURSOR_WAIT:
darin's avatar
darin committed
738
            return waitCursor();
darin's avatar
darin committed
739
        case CURSOR_HELP:
darin's avatar
darin committed
740
            return helpCursor();
darin's avatar
darin committed
741
        case CURSOR_DEFAULT:
darin's avatar
darin committed
742
            return pointerCursor();
darin's avatar
darin committed
743
    }
darin's avatar
darin committed
744
    return pointerCursor();
darin's avatar
darin committed
745
746
}

darin's avatar
darin committed
747
void FrameView::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent)
kocienda's avatar
kocienda committed
748
{
mjs's avatar
mjs committed
749
750
751
752
    // in Radar 3703768 we saw frequent crashes apparently due to the
    // part being null here, which seems impossible, so check for nil
    // but also assert so that we can try to figure this out in debug
    // builds, if it happens.
darin's avatar
darin committed
753
    ASSERT(m_frame);
darin's avatar
darin committed
754
755
    if (!m_frame || !m_frame->document())
        return;
kocienda's avatar
kocienda committed
756

ap's avatar
ap committed
757
758
    RefPtr<FrameView> protector(this);
    
adele's avatar
adele committed
759
760
761
    if (d->hoverTimer.isActive())
        d->hoverTimer.stop();

ap's avatar
ap committed
762
763
764
765
766
    if (d->resizingFrameSet) {
        dispatchMouseEvent(mousemoveEvent, d->resizingFrameSet.get(), false, 0, mouseEvent, false);
        return;
    }

767
768
    // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
    // if we are allowed to select.
darin's avatar
darin committed
769
770
    // This means that :hover and :active freeze in the state they were in when the mouse
    // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
ap's avatar
ap committed
771
772
773
    MouseEventWithHitTestResults mev = prepareMouseEvent(d->mousePressed && m_frame->mouseDownMayStartSelect(),
        d->mousePressed, true, mouseEvent);

thatcher's avatar
thatcher committed
774
    if (d->oldSubframe && d->oldSubframe->tree()->isDescendantOf(m_frame.get()))
ap's avatar
ap committed
775
        m_frame->passSubframeEventToSubframe(mev, d->oldSubframe.get());
darin's avatar
darin committed
776

darin's avatar
darin committed
777
    bool swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
adele's avatar
adele committed
778
779
    
    if (d->m_resizeLayer && d->m_resizeLayer->inResizeMode())
780
        d->m_resizeLayer->resize(mouseEvent, d->offsetFromResizeCorner);
adele's avatar
adele committed
781

darin's avatar
darin committed
782
    if (!swallowEvent)
darin's avatar
darin committed
783
        m_frame->handleMouseMoveEvent(mev);
ap's avatar
ap committed
784
785
786
787
788
    
    RefPtr<Frame> newSubframe = subframeForEvent(mev);
    
    if (newSubframe && d->oldSubframe != newSubframe)
        m_frame->passSubframeEventToSubframe(mev, newSubframe.get());
789
790
791
    else {
        if (RenderLayer::gScrollBar && !d->mousePressed)
            RenderLayer::gScrollBar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
ap's avatar
ap committed
792
        setCursor(selectCursor(mev, m_frame.get(), d->mousePressed));
793
794
    }

ap's avatar
ap committed
795
    d->oldSubframe = newSubframe;
796
797
}

798
void FrameView::invalidateClick()
darin's avatar
darin committed
799
800
{
    d->clickCount = 0;
darin's avatar
darin committed
801
    d->clickNode = 0;
darin's avatar
darin committed
802
803
}

adele's avatar
adele committed
804
805
806
807
808
bool FrameView::mousePressed()
{
    return d->mousePressed;
}

darin's avatar
darin committed
809
void FrameView::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
kocienda's avatar
kocienda committed
810
{
darin's avatar
darin committed
811
812
    if (!m_frame->document())
        return;
kocienda's avatar
kocienda committed
813

814
    RefPtr<FrameView> protector(this);
darin's avatar
darin committed
815

816
817
    d->mousePressed = false;

ap's avatar
ap committed
818
819
820
821
822
    if (d->resizingFrameSet) {
        dispatchMouseEvent(mouseupEvent, d->resizingFrameSet.get(), true, d->clickCount, mouseEvent, false);
        return;
    }

ap's avatar
ap committed
823
    MouseEventWithHitTestResults mev = prepareMouseEvent(false, false, false, mouseEvent);
darin's avatar
darin committed