void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker) { ASSERT(newMarker.endOffset() >= newMarker.startOffset()); if (newMarker.endOffset() == newMarker.startOffset()) return; m_possiblyExistingMarkerTypes.add(newMarker.type()); MarkerList* list = m_markers.get(node); if (!list) { list = new MarkerList; list->append(RenderedDocumentMarker(newMarker)); m_markers.set(node, list); } else { RenderedDocumentMarker toInsert(newMarker); size_t numMarkers = list->size(); size_t i; // Iterate over all markers whose start offset is less than or equal to the new marker's. // If one of them is of the same type as the new marker and touches it or intersects with it // (there is at most one), remove it and adjust the new marker's start offset to encompass it. for (i = 0; i < numMarkers; ++i) { DocumentMarker marker = list->at(i); if (marker.startOffset() > toInsert.startOffset()) break; if (marker.type() == toInsert.type() && marker.endOffset() >= toInsert.startOffset()) { toInsert.setStartOffset(marker.startOffset()); list->remove(i); numMarkers--; break; } } size_t j = i; // Iterate over all markers whose end offset is less than or equal to the new marker's, // removing markers of the same type as the new marker which touch it or intersect with it, // adjusting the new marker's end offset to cover them if necessary. while (j < numMarkers) { DocumentMarker marker = list->at(j); if (marker.startOffset() > toInsert.endOffset()) break; if (marker.type() == toInsert.type()) { list->remove(j); if (toInsert.endOffset() <= marker.endOffset()) { toInsert.setEndOffset(marker.endOffset()); break; } numMarkers--; } else j++; } // At this point i points to the node before which we want to insert. list->insert(i, RenderedDocumentMarker(toInsert)); } // repaint the affected node if (node->renderer()) node->renderer()->repaint(); }
void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker) { if (length <= 0) return; if (!possiblyHasMarkers(markerTypes)) return; ASSERT(!(m_markers.isEmpty())); MarkerList* list = m_markers.get(node); if (!list) return; bool docDirty = false; unsigned endOffset = startOffset + length; for (size_t i = 0; i < list->size();) { DocumentMarker marker = list->at(i); // markers are returned in order, so stop if we are now past the specified range if (marker.startOffset() >= endOffset) break; // skip marker that is wrong type or before target if (marker.endOffset() <= startOffset || !markerTypes.contains(marker.type())) { i++; continue; } // at this point we know that marker and target intersect in some way docDirty = true; // pitch the old marker list->remove(i); if (shouldRemovePartiallyOverlappingMarker) // Stop here. Don't add resulting slices back. continue; // add either of the resulting slices that are left after removing target if (startOffset > marker.startOffset()) { DocumentMarker newLeft = marker; newLeft.setEndOffset(startOffset); list->insert(i, RenderedDocumentMarker(newLeft)); // i now points to the newly-inserted node, but we want to skip that one i++; } if (marker.endOffset() > endOffset) { DocumentMarker newRight = marker; newRight.setStartOffset(endOffset); list->insert(i, RenderedDocumentMarker(newRight)); // i now points to the newly-inserted node, but we want to skip that one i++; } } if (list->isEmpty()) { m_markers.remove(node); if (m_markers.isEmpty()) m_possiblyExistingMarkerTypes = 0; } // repaint the affected node if (docDirty && node->renderer()) node->renderer()->repaint(); }