c8193a639a87a79e1076aa29ff33a684b1072f02
[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 IntRect RenderCanvas::selectionRect() const
255 {
256     typedef HashMap<RenderObject*, SelectionInfo*> SelectionMap;
257     SelectionMap selectedObjects;
258
259     RenderObject* os = m_selectionStart;
260     while (os) {
261         RenderObject* no = 0;
262         if (os != m_selectionEnd) {
263             if (!(no = os->firstChild())) {
264                 if (!(no = os->nextSibling())) {
265                     no = os->parent();
266                     while (no && no != m_selectionEnd && !no->nextSibling())
267                         no = no->parent();
268                     if (no && no != m_selectionEnd)
269                         no = no->nextSibling();
270                 }
271             }
272         }
273         
274         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
275             // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
276 //          assert(!selectedObjects.get(os));
277             selectedObjects.set(os, new SelectionInfo(os));
278             RenderBlock* cb = os->containingBlock();
279             while (cb && !cb->isCanvas()) {
280                 SelectionInfo* blockInfo = selectedObjects.get(cb);
281                 if (blockInfo)
282                     break;
283                 selectedObjects.set(cb, new SelectionInfo(cb));
284                 cb = cb->containingBlock();
285             }
286         }
287         
288         os = no;
289     }
290
291     // Now create a single bounding box rect that encloses the whole selection.
292     IntRect selRect;
293     SelectionMap::iterator end = selectedObjects.end();
294     for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) {
295         SelectionInfo* info = i->second;
296         selRect.unite(info->rect());
297         delete info;
298     }
299     return selRect;
300 }
301
302 void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep)
303 {
304     // Make sure both our start and end objects are defined. 
305     // Check www.msnbc.com and try clicking around to find the case where this happened.
306     if ((s && !e) || (e && !s))
307         return;
308
309     // Just return if the selection hasn't changed.
310     if (m_selectionStart == s && m_selectionStartPos == sp &&
311         m_selectionEnd == e && m_selectionEndPos == ep)
312         return;
313
314     // Record the old selected objects.  These will be used later
315     // when we compare against the new selected objects.
316     int oldStartPos = m_selectionStartPos;
317     int oldEndPos = m_selectionEndPos;
318
319     // Objects each have a single selection rect to examine.
320     typedef HashMap<RenderObject*, SelectionInfo*> SelectedObjectMap;
321     SelectedObjectMap oldSelectedObjects;
322     SelectedObjectMap newSelectedObjects;
323
324     // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks.
325     // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise
326     // the union of those rects might remain the same even when changes have occurred.
327     typedef HashMap<RenderBlock*, BlockSelectionInfo*> SelectedBlockMap;
328     SelectedBlockMap oldSelectedBlocks;
329     SelectedBlockMap newSelectedBlocks;
330
331     RenderObject* os = m_selectionStart;
332     while (os) {
333         RenderObject* no = 0;
334         if (os != m_selectionEnd) {
335             if (!(no = os->firstChild())) {
336                 if (!(no = os->nextSibling())) {
337                     no = os->parent();
338                     while (no && no != m_selectionEnd && !no->nextSibling())
339                         no = no->parent();
340                     if (no && no != m_selectionEnd)
341                         no = no->nextSibling();
342                 }
343             }
344         }
345
346         if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) {
347             // Blocks are responsible for painting line gaps and margin gaps.  They must be examined as well.
348             oldSelectedObjects.set(os, new SelectionInfo(os));
349             RenderBlock* cb = os->containingBlock();
350             while (cb && !cb->isCanvas()) {
351                 BlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb);
352                 if (blockInfo)
353                     break;
354                 oldSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
355                 cb = cb->containingBlock();
356             }
357         }
358
359         os = no;
360     }
361
362     // Now clear the selection.
363     SelectedObjectMap::iterator oldObjectsEnd = oldSelectedObjects.end();
364     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i)
365         i->first->setSelectionState(SelectionNone);
366
367     // set selection start and end
368     m_selectionStart = s;
369     m_selectionStartPos = sp;
370     m_selectionEnd = e;
371     m_selectionEndPos = ep;
372
373     // Update the selection status of all objects between m_selectionStart and m_selectionEnd
374     if (s && s == e)
375         s->setSelectionState(SelectionBoth);
376     else {
377         if (s)
378             s->setSelectionState(SelectionStart);
379         if (e)
380             e->setSelectionState(SelectionEnd);
381     }
382
383     RenderObject* o = s;
384     while (o) {
385         RenderObject* no = 0;
386         if (o != s && o != e && o->canBeSelectionLeaf())
387             o->setSelectionState(SelectionInside);
388         
389         if (o != e) {
390             if (!(no = o->firstChild())) {
391                 if ( !(no = o->nextSibling())) {
392                     no = o->parent();
393                     while (no && no != e && !no->nextSibling())
394                         no = no->parent();
395                     if (no && no != e)
396                         no = no->nextSibling();
397                 }
398             }
399         }
400         
401         o=no;
402     }
403
404     // Now that the selection state has been updated for the new objects, walk them again and
405     // put them in the new objects list.
406     o = s;
407     while (o) {
408         RenderObject* no = 0;
409         if (o != e) {
410             if (!(no = o->firstChild())) {
411                 if ( !(no = o->nextSibling())) {
412                     no = o->parent();
413                     while (no && no != e && !no->nextSibling())
414                         no = no->parent();
415                     if (no && no != e)
416                         no = no->nextSibling();
417                 }
418             }
419         }
420         
421         if ((o->canBeSelectionLeaf() || o == s || o == e) && o->selectionState() != SelectionNone) {
422             newSelectedObjects.set(o, new SelectionInfo(o));
423             RenderBlock* cb = o->containingBlock();
424             while (cb && !cb->isCanvas()) {
425                 BlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb);
426                 if (blockInfo)
427                     break;
428                 newSelectedBlocks.set(cb, new BlockSelectionInfo(cb));
429                 cb = cb->containingBlock();
430             }
431         }
432
433         o=no;
434     }
435
436     if (!m_view)
437         return;
438
439     // Have any of the old selected objects changed compared to the new selection?
440     for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) {
441         RenderObject* obj = i->first;
442         SelectionInfo* newInfo = newSelectedObjects.get(obj);
443         SelectionInfo* oldInfo = i->second;
444         if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() ||
445             (m_selectionStart == obj && oldStartPos != m_selectionStartPos) ||
446             (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) {
447             m_view->updateContents(oldInfo->rect());
448             if (newInfo) {
449                 m_view->updateContents(newInfo->rect());
450                 newSelectedObjects.remove(obj);
451                 delete newInfo;
452             }
453         }
454         delete oldInfo;
455     }
456     
457     // Any new objects that remain were not found in the old objects dict, and so they need to be updated.
458     SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end();
459     for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) {
460         SelectionInfo* newInfo = i->second;
461         m_view->updateContents(newInfo->rect());
462         delete newInfo;
463     }
464
465     // Have any of the old blocks changed?
466     SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end();
467     for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) {
468         RenderBlock* block = i->first;
469         BlockSelectionInfo* newInfo = newSelectedBlocks.get(block);
470         BlockSelectionInfo* oldInfo = i->second;
471         if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) {
472             m_view->updateContents(oldInfo->rects());
473             if (newInfo) {
474                 m_view->updateContents(newInfo->rects());
475                 newSelectedBlocks.remove(block);
476                 delete newInfo;
477             }
478         }
479         delete oldInfo;
480     }
481     
482     // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated.
483     SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end();
484     for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) {
485         BlockSelectionInfo* newInfo = i->second;
486         m_view->updateContents(newInfo->rects());
487         delete newInfo;
488     }
489 }
490
491 void RenderCanvas::clearSelection()
492 {
493     setSelection(0, -1, 0, -1);
494 }
495
496 void RenderCanvas::selectionStartEnd(int& spos, int& epos)
497 {
498     spos = m_selectionStartPos;
499     epos = m_selectionEndPos;
500 }
501
502 void RenderCanvas::updateWidgetPositions()
503 {
504     RenderObjectSet::iterator end = m_widgets.end();
505     for (RenderObjectSet::iterator it = m_widgets.begin(); it != end; ++it) {
506         (*it)->updateWidgetPosition();
507     }
508 }
509
510 void RenderCanvas::addWidget(RenderObject *o)
511 {
512     m_widgets.add(o);
513 }
514
515 void RenderCanvas::removeWidget(RenderObject *o)
516 {
517     m_widgets.remove(o);
518 }
519
520
521
522 IntRect RenderCanvas::viewRect() const
523 {
524     if (m_printingMode)
525         return IntRect(0, 0, m_width, m_height);
526     if (m_view)
527         return IntRect(m_view->contentsX(),
528             m_view->contentsY(),
529             m_view->visibleWidth(),
530             m_view->visibleHeight());
531     return IntRect();
532 }
533
534 int RenderCanvas::docHeight() const
535 {
536     int h;
537     if (m_printingMode || !m_view)
538         h = m_height;
539     else
540         h = m_view->visibleHeight();
541
542     int lowestPos = lowestPosition();
543     if( lowestPos > h )
544         h = lowestPos;
545
546     // FIXME: This doesn't do any margin collapsing.
547     // Instead of this dh computation we should keep the result
548     // when we call RenderBlock::layout.
549     int dh = 0;
550     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
551         dh += c->height() + c->marginTop() + c->marginBottom();
552     }
553     if( dh > h )
554         h = dh;
555
556     return h;
557 }
558
559 int RenderCanvas::docWidth() const
560 {
561     int w;
562     if (m_printingMode || !m_view)
563         w = m_width;
564     else
565         w = m_view->visibleWidth();
566
567     int rightmostPos = rightmostPosition();
568     if( rightmostPos > w )
569         w = rightmostPos;
570
571     for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
572         int dw = c->width() + c->marginLeft() + c->marginRight();
573         if( dw > w )
574             w = dw;
575     }
576     return w;
577 }
578
579 // The idea here is to take into account what object is moving the pagination point, and
580 // thus choose the best place to chop it.
581 void RenderCanvas::setBestTruncatedAt(int y, RenderObject *forRenderer, bool forcedBreak)
582 {
583     // Nobody else can set a page break once we have a forced break.
584     if (m_forcedPageBreak) return;
585     
586     // Forced breaks always win over unforced breaks.
587     if (forcedBreak) {
588         m_forcedPageBreak = true;
589         m_bestTruncatedAt = y;
590         return;
591     }
592     
593     // prefer the widest object who tries to move the pagination point
594     int width = forRenderer->width();
595     if (width > m_truncatorWidth) {
596         m_truncatorWidth = width;
597         m_bestTruncatedAt = y;
598     }
599 }
600
601 }