LayoutTests:
[WebKit-https.git] / WebCore / rendering / RenderCanvas.cpp
1 /**
2  * This file is part of the HTML widget for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include "RenderCanvas.h"
25
26 #include "Document.h"
27 #include "Element.h"
28 #include "FrameView.h"
29 #include "GraphicsContext.h"
30 #include "RenderLayer.h"
31
32 namespace WebCore {
33
34 //#define BOX_DEBUG
35
36 RenderCanvas::RenderCanvas(Node* node, FrameView *view)
37     : RenderBlock(node)
38 {
39     // Clear our anonymous bit, set because RenderObject assumes
40     // any renderer with document as the node is anonymous.
41     setIsAnonymous(false);
42         
43     // init RenderObject attributes
44     setInline(false);
45
46     m_view = view;
47     // try to contrain the width to the views width
48
49     m_minWidth = 0;
50     m_height = 0;
51
52     m_width = m_minWidth;
53     m_maxWidth = m_minWidth;
54
55     setPositioned(true); // to 0,0 :)
56
57     m_printingMode = false;
58     m_printImages = true;
59
60     m_maximalOutlineSize = 0;
61     
62     m_selectionStart = 0;
63     m_selectionEnd = 0;
64     m_selectionStartPos = -1;
65     m_selectionEndPos = -1;
66
67     // Create a new root layer for our layer hierarchy.
68     m_layer = new (node->getDocument()->renderArena()) RenderLayer(this);
69 }
70
71 RenderCanvas::~RenderCanvas()
72 {
73 }
74
75 void RenderCanvas::calcHeight()
76 {
77     if (!m_printingMode && m_view)
78         m_height = m_view->visibleHeight();
79 }
80
81 void RenderCanvas::calcWidth()
82 {
83     if (!m_printingMode && m_view)
84         m_width = m_view->visibleWidth();
85     m_marginLeft = 0;
86     m_marginRight = 0;
87 }
88
89 void RenderCanvas::calcMinMaxWidth()
90 {
91     KHTMLAssert( !minMaxKnown() );
92
93     RenderBlock::calcMinMaxWidth();
94
95     m_maxWidth = m_minWidth;
96
97     setMinMaxKnown();
98 }
99
100 void RenderCanvas::layout()
101 {
102     KHTMLAssert(!view()->inLayout());
103     
104     if (m_printingMode)
105         m_minWidth = m_width;
106
107     setChildNeedsLayout(true);
108     setMinMaxKnown(false);
109     for (RenderObject *c = firstChild(); c; c = c->nextSibling())
110         c->setChildNeedsLayout(true);
111
112     if ( recalcMinMax() )
113         recalcMinMaxWidths();
114
115     RenderBlock::layout();
116
117     int docw = docWidth();
118     int doch = docHeight();
119
120     if (!m_printingMode) {
121         setWidth(m_view->visibleWidth());
122         setHeight(m_view->visibleHeight());
123     }
124
125     // ### we could maybe do the call below better and only pass true if the docsize changed.
126     layoutPositionedObjects( true );
127
128     layer()->setHeight(kMax(doch, m_height));
129     layer()->setWidth(kMax(docw, m_width));
130     
131     setNeedsLayout(false);
132 }
133
134 bool RenderCanvas::absolutePosition(int &xPos, int &yPos, bool f)
135 {
136     if ( f && m_view) {
137         xPos = m_view->contentsX();
138         yPos = m_view->contentsY();
139     } else
140         xPos = yPos = 0;
141     return true;
142 }
143
144 void RenderCanvas::paint(PaintInfo& i, int _tx, int _ty)
145 {
146 #ifdef DEBUG_LAYOUT
147     kdDebug( 6040 ) << renderName() << "(RenderCanvas) " << this << " ::paintObject() w/h = (" << width() << "/" << height() << ")" << endl;
148 #endif
149     
150     // Cache the print rect because the dirty rect could get changed during painting.
151     if (m_printingMode)
152         setPrintRect(i.r);
153     
154     // 1. paint background, borders etc
155     if (i.phase == PaintActionBlockBackground) {
156         paintBoxDecorations(i, _tx, _ty);
157         return;
158     }
159     
160     // 2. paint contents
161     for (RenderObject *child = firstChild(); child; child = child->nextSibling())
162         if (!child->layer() && !child->isFloating())
163             child->paint(i, _tx, _ty);
164
165     if (m_view)
166     {
167         _tx += m_view->contentsX();
168         _ty += m_view->contentsY();
169     }
170     
171     // 3. paint floats.
172     if (i.phase == PaintActionFloat)
173         paintFloats(i, _tx, _ty);
174         
175 #ifdef BOX_DEBUG
176     outlineBox(i.p, _tx, _ty);
177 #endif
178 }
179
180 void RenderCanvas::paintBoxDecorations(PaintInfo& i, int _tx, int _ty)
181 {
182     // Check to see if we are enclosed by a transparent layer.  If so, we cannot blit
183     // when scrolling, and we need to use slow repaints.
184     Element* elt = element()->getDocument()->ownerElement();
185     if (view() && elt) {
186         RenderLayer* layer = elt->renderer()->enclosingLayer();
187         if (layer->isTransparent() || layer->transparentAncestor())
188             view()->useSlowRepaints();
189     }
190     
191     if ((firstChild() && firstChild()->style()->visibility() == VISIBLE) || !view())
192         return;
193
194     // This code typically only executes if the root element's visibility has been set to hidden.
195     // Only fill with white if we're the root document, since iframes/frames with
196     // no background in the child document should show the parent's background.
197     if (elt || view()->isTransparent())
198         view()->useSlowRepaints(); // The parent must show behind the child.
199     else
200         i.p->fillRect(i.r, Color(Color::white));
201 }
202
203 void RenderCanvas::repaintViewRectangle(const IntRect& ur, bool immediate)
204 {
205     if (m_printingMode || ur.width() == 0 || ur.height() == 0) return;
206
207     IntRect vr = viewRect();
208     if (m_view && ur.intersects(vr)) {
209         // We always just invalidate the root view, since we could be an iframe that is clipped out
210         // or even invisible.
211         IntRect r = intersection(ur, vr);
212         Element* elt = element()->getDocument()->ownerElement();
213         if (!elt)
214             m_view->repaintRectangle(r, immediate);
215         else {
216             // Subtract out the contentsX and contentsY offsets to get our coords within the viewing
217             // rectangle.
218             r.move(-m_view->contentsX(), -m_view->contentsY());
219
220             RenderObject* obj = elt->renderer();
221             // FIXME: Hardcoded offsets here are not good.
222             int yFrameOffset = m_view->hasBorder() ? 2 : 0;
223             int xFrameOffset = m_view->hasBorder() ? 1 : 0;
224             r.move(obj->borderLeft() + obj->paddingLeft() + xFrameOffset,
225                 obj->borderTop() + obj->paddingTop() + yFrameOffset);
226             obj->repaintRectangle(r, immediate);
227         }
228     }
229 }
230
231 IntRect RenderCanvas::getAbsoluteRepaintRect()
232 {
233     IntRect result;
234     if (m_view && !m_printingMode)
235         result = IntRect(m_view->contentsX(), m_view->contentsY(),
236                        m_view->visibleWidth(), m_view->visibleHeight());
237     return result;
238 }
239
240 void RenderCanvas::computeAbsoluteRepaintRect(IntRect& r, bool f)
241 {
242     if (m_printingMode)
243         return;
244
245     if (f && m_view)
246         r.move(m_view->contentsX(), m_view->contentsY());
247 }
248
249 void RenderCanvas::absoluteRects(DeprecatedValueList<IntRect>& rects, int _tx, int _ty)
250 {
251     rects.append(IntRect(_tx, _ty, m_layer->width(), m_layer->height()));
252 }
253
254 RenderObject* rendererAfterPosition(RenderObject* object, unsigned offset)
255 {
256     if (!object)
257         return 0;
258     RenderObject* child = object->childAt(offset);
259     return child ? child : object->nextInPreOrderAfterChildren();
260 }
261
262 IntRect RenderCanvas::selectionRect() const
263 {
264     typedef HashMap<RenderObject*, SelectionInfo*> SelectionMap;
265     SelectionMap selectedObjects;
266
267     RenderObject* os = m_selectionStart;
268     RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
269     while (os && os != stop) {
270         
271         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
272             // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
273 //          assert(!selectedObjects.get(os));
274             selectedObjects.set(os, new SelectionInfo(os));
275             RenderBlock* cb = os->containingBlock();
276             while (cb && !cb->isCanvas()) {
277                 SelectionInfo* blockInfo = selectedObjects.get(cb);
278                 if (blockInfo)
279                     break;
280                 selectedObjects.set(cb, new SelectionInfo(cb));
281                 cb = cb->containingBlock();
282             }
283         }
284         
285         os = os->nextInPreOrder();
286     }
287
288     // Now create a single bounding box rect that encloses the whole selection.
289     IntRect selRect;
290     SelectionMap::iterator end = selectedObjects.end();
291     for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) {
292         SelectionInfo* info = i->second;
293         selRect.unite(info->rect());
294         delete info;
295     }
296     return selRect;
297 }
298
299 void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep)
300 {
301     // Make sure both our start and end objects are defined. 
302     // Check www.msnbc.com and try clicking around to find the case where this happened.
303     if ((s && !e) || (e && !s))
304         return;
305
306     // Just return if the selection hasn't changed.
307     if (m_selectionStart == s && m_selectionStartPos == sp &&
308         m_selectionEnd == e && m_selectionEndPos == ep)
309         return;
310
311     // Record the old selected objects.  These will be used later
312     // when we compare against the new selected objects.
313     int oldStartPos = m_selectionStartPos;
314     int oldEndPos = m_selectionEndPos;
315
316     // Objects each have a single selection rect to examine.
317     typedef HashMap<RenderObject*, SelectionInfo*> SelectedObjectMap;
318     SelectedObjectMap oldSelectedObjects;
319     SelectedObjectMap newSelectedObjects;
320
321     // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks.
322     // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise
323     // the union of those rects might remain the same even when changes have occurred.
324     typedef HashMap<RenderBlock*, BlockSelectionInfo*> SelectedBlockMap;
325     SelectedBlockMap oldSelectedBlocks;
326     SelectedBlockMap newSelectedBlocks;
327
328     RenderObject* os = m_selectionStart;
329     RenderObject* stop = rendererAfterPosition(m_selectionEnd, m_selectionEndPos);
330     while (os && os != stop) {
331         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
332             // Blocks are responsible for painting line gaps and margin gaps.  They must be examined as well.
333             oldSelectedObjects.set(os, new SelectionInfo(os));
334             RenderBlock* cb = os->containingBlock();
335             while (cb && !cb->isCanvas()) {
336                 BlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb);
337                 if (blockInfo)
338                     break;
339                 oldSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
340                 cb = cb->containingBlock();
341             }
342         }
343         
344         os = os->nextInPreOrder();
345     }
346
347     // Now clear the selection.
348     SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end();
349     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i)
350         i->first->setSelectionState(SelectionNone);
351
352     // set selection start and end
353     m_selectionStart = s;
354     m_selectionStartPos = sp;
355     m_selectionEnd = e;
356     m_selectionEndPos = ep;
357
358     // Update the selection status of all objects between m_selectionStart and m_selectionEnd
359     if (s && s == e)
360         s->setSelectionState(SelectionBoth);
361     else {
362         if (s)
363             s->setSelectionState(SelectionStart);
364         if (e)
365             e->setSelectionState(SelectionEnd);
366     }
367
368     RenderObject* o = s;
369     stop = rendererAfterPosition(e, ep);
370     
371     while (o && o != stop) {
372         if (o != s && o != e && o->canBeSelectionLeaf())
373             o->setSelectionState(SelectionInside);
374         o = o->nextInPreOrder();
375     }
376
377     // Now that the selection state has been updated for the new objects, walk them again and
378     // put them in the new objects list.
379     o = s;
380     while (o && o != stop) {
381         
382         if ((o->canBeSelectionLeaf() || o == s || o == e) && o->selectionState() != SelectionNone) {
383             newSelectedObjects.set(o, new SelectionInfo(o));
384             RenderBlock* cb = o->containingBlock();
385             while (cb && !cb->isCanvas()) {
386                 BlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb);
387                 if (blockInfo)
388                     break;
389                 newSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
390                 cb = cb->containingBlock();
391             }
392         }
393
394         o = o->nextInPreOrder();
395     }
396
397     if (!m_view)
398         return;
399
400     // Have any of the old selected objects changed compared to the new selection?
401     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) {
402         RenderObject* obj = i->first;
403         SelectionInfo* newInfo = newSelectedObjects.get(obj);
404         SelectionInfo* oldInfo = i->second;
405         if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() ||
406             (m_selectionStart == obj && oldStartPos != m_selectionStartPos) ||
407             (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) {
408             m_view->updateContents(oldInfo->rect());
409             if (newInfo) {
410                 m_view->updateContents(newInfo->rect());
411                 newSelectedObjects.remove(obj);
412                 delete newInfo;
413             }
414         }
415         delete oldInfo;
416     }
417     
418     // Any new objects that remain were not found in the old objects dict, and so they need to be updated.
419     SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end();
420     for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) {
421         SelectionInfo* newInfo = i->second;
422         m_view->updateContents(newInfo->rect());
423         delete newInfo;
424     }
425
426     // Have any of the old blocks changed?
427     SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end();
428     for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) {
429         RenderBlock* block = i->first;
430         BlockSelectionInfo* newInfo = newSelectedBlocks.get(block);
431         BlockSelectionInfo* oldInfo = i->second;
432         if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) {
433             m_view->updateContents(oldInfo->rects());
434             if (newInfo) {
435                 m_view->updateContents(newInfo->rects());
436                 newSelectedBlocks.remove(block);
437                 delete newInfo;
438             }
439         }
440         delete oldInfo;
441     }
442     
443     // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated.
444     SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end();
445     for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) {
446         BlockSelectionInfo* newInfo = i->second;
447         m_view->updateContents(newInfo->rects());
448         delete newInfo;
449     }
450 }
451
452 void RenderCanvas::clearSelection()
453 {
454     setSelection(0, -1, 0, -1);
455 }
456
457 void RenderCanvas::selectionStartEnd(int& spos, int& epos)
458 {
459     spos = m_selectionStartPos;
460     epos = m_selectionEndPos;
461 }
462
463 void RenderCanvas::updateWidgetPositions()
464 {
465     RenderObjectSet::iterator end = m_widgets.end();
466     for (RenderObjectSet::iterator it = m_widgets.begin(); it != end; ++it) {
467         (*it)->updateWidgetPosition();
468     }
469 }
470
471 void RenderCanvas::addWidget(RenderObject *o)
472 {
473     m_widgets.add(o);
474 }
475
476 void RenderCanvas::removeWidget(RenderObject *o)
477 {
478     m_widgets.remove(o);
479 }
480
481
482
483 IntRect RenderCanvas::viewRect() const
484 {
485     if (m_printingMode)
486         return IntRect(0, 0, m_width, m_height);
487     if (m_view)
488         return IntRect(m_view->contentsX(),
489             m_view->contentsY(),
490             m_view->visibleWidth(),
491             m_view->visibleHeight());
492     return IntRect();
493 }
494
495 int RenderCanvas::docHeight() const
496 {
497     int h;
498     if (m_printingMode || !m_view)
499         h = m_height;
500     else
501         h = m_view->visibleHeight();
502
503     int lowestPos = lowestPosition();
504     if( lowestPos > h )
505         h = lowestPos;
506
507     // FIXME: This doesn't do any margin collapsing.
508     // Instead of this dh computation we should keep the result
509     // when we call RenderBlock::layout.
510     int dh = 0;
511     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
512         dh += c->height() + c->marginTop() + c->marginBottom();
513     }
514     if( dh > h )
515         h = dh;
516
517     return h;
518 }
519
520 int RenderCanvas::docWidth() const
521 {
522     int w;
523     if (m_printingMode || !m_view)
524         w = m_width;
525     else
526         w = m_view->visibleWidth();
527
528     int rightmostPos = rightmostPosition();
529     if( rightmostPos > w )
530         w = rightmostPos;
531
532     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
533         int dw = c->width() + c->marginLeft() + c->marginRight();
534         if( dw > w )
535             w = dw;
536     }
537     return w;
538 }
539
540 // The idea here is to take into account what object is moving the pagination point, and
541 // thus choose the best place to chop it.
542 void RenderCanvas::setBestTruncatedAt(int y, RenderObject *forRenderer, bool forcedBreak)
543 {
544     // Nobody else can set a page break once we have a forced break.
545     if (m_forcedPageBreak) return;
546     
547     // Forced breaks always win over unforced breaks.
548     if (forcedBreak) {
549         m_forcedPageBreak = true;
550         m_bestTruncatedAt = y;
551         return;
552     }
553     
554     // prefer the widest object who tries to move the pagination point
555     int width = forRenderer->width();
556     if (width > m_truncatorWidth) {
557         m_truncatorWidth = width;
558         m_bestTruncatedAt = y;
559     }
560 }
561
562 }