void RenderCanvas::setSelection(RenderObject *s, int sp, RenderObject *e, int ep) { // Check we got valid renderobjects. www.msnbc.com and clicking // around, to find the case where this happened. if ( !s || !e ) { kdWarning(6040) << "RenderCanvas::setSelection() called with start=" << s << " end=" << e << endl; return; } // kdDebug( 6040 ) << "RenderCanvas::setSelection(" << s << "," << sp << "," << e << "," << ep << ")" << endl; bool changedSelectionBorder = ( s != m_selectionStart || e != m_selectionEnd ); // Cut out early if the selection hasn't changed. if ( !changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos == ep ) return; // Record the old selected objects. Will be used later // to delta against the selected objects. RenderObject *oldStart = m_selectionStart; int oldStartPos = m_selectionStartPos; RenderObject *oldEnd = m_selectionEnd; int oldEndPos = m_selectionEndPos; QPtrList<RenderObject> oldSelectedInside; QPtrList<RenderObject> newSelectedInside; RenderObject *os = oldStart; while (os && os != oldEnd) { RenderObject* no; if ( !(no = os->firstChild()) ){ if ( !(no = os->nextSibling()) ) { no = os->parent(); while (no && !no->nextSibling()) no = no->parent(); if (no) no = no->nextSibling(); } } if (os->selectionState() == SelectionInside && !oldSelectedInside.containsRef(os)) oldSelectedInside.append(os); os = no; } if (changedSelectionBorder) clearSelection(false); while (s->firstChild()) s = s->firstChild(); while (e->lastChild()) e = e->lastChild(); #if 0 bool changedSelectionBorder = ( s != m_selectionStart || e != m_selectionEnd ); if ( !changedSelectionBorder && m_selectionStartPos == sp && m_selectionEndPos = ep ) return; #endif // set selection start if (m_selectionStart) m_selectionStart->setIsSelectionBorder(false); m_selectionStart = s; if (m_selectionStart) m_selectionStart->setIsSelectionBorder(true); m_selectionStartPos = sp; // set selection end if (m_selectionEnd) m_selectionEnd->setIsSelectionBorder(false); m_selectionEnd = e; if (m_selectionEnd) m_selectionEnd->setIsSelectionBorder(true); m_selectionEndPos = ep; #if 0 kdDebug( 6040 ) << "old selection (" << oldStart << "," << oldStartPos << "," << oldEnd << "," << oldEndPos << ")" << endl; kdDebug( 6040 ) << "new selection (" << s << "," << sp << "," << e << "," << ep << ")" << endl; #endif // update selection status of all objects between m_selectionStart and m_selectionEnd RenderObject* o = s; while (o && o!=e) { o->setSelectionState(SelectionInside); // kdDebug( 6040 ) << "setting selected " << o << ", " << o->isText() << endl; RenderObject* no; if ( !(no = o->firstChild()) ) if ( !(no = o->nextSibling()) ) { no = o->parent(); while (no && !no->nextSibling()) no = no->parent(); if (no) no = no->nextSibling(); } if (o->selectionState() == SelectionInside && !newSelectedInside.containsRef(o)) newSelectedInside.append(o); o=no; } s->setSelectionState(SelectionStart); e->setSelectionState(SelectionEnd); if(s == e) s->setSelectionState(SelectionBoth); if (!m_view) return; newSelectedInside.removeRef(s); newSelectedInside.removeRef(e); QRect updateRect; // Don't use repaint() because it will cause all rects to // be united (see khtmlview::scheduleRepaint()). Instead // just draw damage rects for objects that have a change // in selection state. // ### for Qt, updateContents will unite them, too. This has to be // circumvented somehow (LS) // Are any of the old fully selected objects not in the new selection? // If so we have to draw them. // Could be faster by building list of non-intersecting rectangles rather // than unioning rectangles. QPtrListIterator<RenderObject> oldIterator(oldSelectedInside); bool firstRect = true; for (; oldIterator.current(); ++oldIterator){ if (!newSelectedInside.containsRef(oldIterator.current())){ if (firstRect){ updateRect = enclosingPositionedRect(oldIterator.current()); firstRect = false; } else updateRect = updateRect.unite(enclosingPositionedRect(oldIterator.current())); } } if (!firstRect){ m_view->updateContents( updateRect ); } // Are any of the new fully selected objects not in the previous selection? // If so we have to draw them. // Could be faster by building list of non-intersecting rectangles rather // than unioning rectangles. QPtrListIterator<RenderObject> newIterator(newSelectedInside); firstRect = true; for (; newIterator.current(); ++newIterator){ if (!oldSelectedInside.containsRef(newIterator.current())){ if (firstRect){ updateRect = enclosingPositionedRect(newIterator.current()); firstRect = false; } else updateRect = updateRect.unite(enclosingPositionedRect(newIterator.current())); } } if (!firstRect) { m_view->updateContents( updateRect ); } // Is the new starting object different, or did the position in the starting // element change? If so we have to draw it. if (oldStart != m_selectionStart || (oldStart == oldEnd && (oldStartPos != m_selectionStartPos || oldEndPos != m_selectionEndPos)) || (oldStart == m_selectionStart && oldStartPos != m_selectionStartPos)){ m_view->updateContents( enclosingPositionedRect(m_selectionStart) ); } // Draw the old selection start object if it's different than the new selection // start object. if (oldStart && oldStart != m_selectionStart){ m_view->updateContents( enclosingPositionedRect(oldStart) ); } // Does the selection span objects and is the new end object different, or did the position // in the end element change? If so we have to draw it. if (/*(oldStart != oldEnd || !oldEnd) &&*/ (oldEnd != m_selectionEnd || (oldEnd == m_selectionEnd && oldEndPos != m_selectionEndPos))){ m_view->updateContents( enclosingPositionedRect(m_selectionEnd) ); } // Draw the old selection end object if it's different than the new selection // end object. if (oldEnd && oldEnd != m_selectionEnd){ m_view->updateContents( enclosingPositionedRect(oldEnd) ); } }