PageRenderTime 75ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/core/editing/markers/DocumentMarkerController.cpp

https://repo.or.cz/blink.git
C++ | 751 lines | 583 code | 113 blank | 55 comment | 166 complexity | cf02dde3dba564d6767a3eaccdad5c67 MD5 | raw file
Possible License(s): BSD-3-Clause, Unlicense, AGPL-1.0, Apache-2.0
  1. /*
  2. * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  3. * (C) 1999 Antti Koivisto (koivisto@kde.org)
  4. * (C) 2001 Dirk Mueller (mueller@kde.org)
  5. * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
  6. * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
  7. * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
  8. * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Library General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Library General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Library General Public License
  21. * along with this library; see the file COPYING.LIB. If not, write to
  22. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  23. * Boston, MA 02110-1301, USA.
  24. *
  25. */
  26. #include "config.h"
  27. #include "core/editing/markers/DocumentMarkerController.h"
  28. #include "core/dom/Node.h"
  29. #include "core/dom/NodeTraversal.h"
  30. #include "core/dom/Range.h"
  31. #include "core/dom/Text.h"
  32. #include "core/editing/iterators/TextIterator.h"
  33. #include "core/editing/markers/RenderedDocumentMarker.h"
  34. #include "core/frame/FrameView.h"
  35. #include "core/layout/LayoutObject.h"
  36. #ifndef NDEBUG
  37. #include <stdio.h>
  38. #endif
  39. namespace blink {
  40. MarkerRemoverPredicate::MarkerRemoverPredicate(const Vector<String>& words)
  41. : m_words(words)
  42. {
  43. }
  44. bool MarkerRemoverPredicate::operator()(const DocumentMarker& documentMarker, const Text& textNode) const
  45. {
  46. unsigned start = documentMarker.startOffset();
  47. unsigned length = documentMarker.endOffset() - documentMarker.startOffset();
  48. String markerText = textNode.data().substring(start, length);
  49. return m_words.contains(markerText);
  50. }
  51. namespace {
  52. DocumentMarker::MarkerTypeIndex MarkerTypeToMarkerIndex(DocumentMarker::MarkerType type)
  53. {
  54. switch (type) {
  55. case DocumentMarker::Spelling:
  56. return DocumentMarker::SpellingMarkerIndex;
  57. case DocumentMarker::Grammar:
  58. return DocumentMarker::GramarMarkerIndex;
  59. case DocumentMarker::TextMatch:
  60. return DocumentMarker::TextMatchMarkerIndex;
  61. case DocumentMarker::InvisibleSpellcheck:
  62. return DocumentMarker::InvisibleSpellcheckMarkerIndex;
  63. case DocumentMarker::Composition:
  64. return DocumentMarker::CompositionMarkerIndex;
  65. }
  66. ASSERT_NOT_REACHED();
  67. return DocumentMarker::SpellingMarkerIndex;
  68. }
  69. } // namespace
  70. inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
  71. {
  72. return m_possiblyExistingMarkerTypes.intersects(types);
  73. }
  74. DocumentMarkerController::DocumentMarkerController()
  75. : m_possiblyExistingMarkerTypes(0)
  76. {
  77. }
  78. DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(DocumentMarkerController);
  79. void DocumentMarkerController::clear()
  80. {
  81. m_markers.clear();
  82. m_possiblyExistingMarkerTypes = 0;
  83. }
  84. void DocumentMarkerController::addMarker(const Position& start, const Position& end, DocumentMarker::MarkerType type, const String& description, uint32_t hash)
  85. {
  86. // Use a TextIterator to visit the potentially multiple nodes the range covers.
  87. for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.advance()) {
  88. addMarker(markedText.currentContainer(), DocumentMarker(type, markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), description, hash));
  89. }
  90. }
  91. void DocumentMarkerController::addTextMatchMarker(const Range* range, bool activeMatch)
  92. {
  93. // Use a TextIterator to visit the potentially multiple nodes the range covers.
  94. for (TextIterator markedText(range->startPosition(), range->endPosition()); !markedText.atEnd(); markedText.advance())
  95. addMarker(markedText.currentContainer(), DocumentMarker(markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), activeMatch));
  96. // Don't invalidate tickmarks here. TextFinder invalidates tickmarks using a throttling algorithm. crbug.com/6819.
  97. }
  98. void DocumentMarkerController::addCompositionMarker(const Position& start, const Position& end, Color underlineColor, bool thick, Color backgroundColor)
  99. {
  100. for (TextIterator markedText(start, end); !markedText.atEnd(); markedText.advance())
  101. addMarker(markedText.currentContainer(), DocumentMarker(markedText.startOffsetInCurrentContainer(), markedText.endOffsetInCurrentContainer(), underlineColor, thick, backgroundColor));
  102. }
  103. void DocumentMarkerController::prepareForDestruction()
  104. {
  105. clear();
  106. }
  107. void DocumentMarkerController::removeMarkers(TextIterator& markedText, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
  108. {
  109. for (; !markedText.atEnd(); markedText.advance()) {
  110. if (!possiblyHasMarkers(markerTypes))
  111. return;
  112. ASSERT(!m_markers.isEmpty());
  113. int startOffset = markedText.startOffsetInCurrentContainer();
  114. int endOffset = markedText.endOffsetInCurrentContainer();
  115. removeMarkers(markedText.currentContainer(), startOffset, endOffset - startOffset, markerTypes, shouldRemovePartiallyOverlappingMarker);
  116. }
  117. }
  118. void DocumentMarkerController::removeMarkers(const EphemeralRange& range, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
  119. {
  120. TextIterator markedText(range.startPosition(), range.endPosition());
  121. DocumentMarkerController::removeMarkers(markedText, markerTypes, shouldRemovePartiallyOverlappingMarker);
  122. }
  123. static bool startsFurther(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv, const DocumentMarker* rhv)
  124. {
  125. return lhv->startOffset() < rhv->startOffset();
  126. }
  127. static bool startsAfter(const OwnPtrWillBeMember<RenderedDocumentMarker>& marker, size_t startOffset)
  128. {
  129. return marker->startOffset() < startOffset;
  130. }
  131. static bool endsBefore(size_t startOffset, const OwnPtrWillBeMember<RenderedDocumentMarker>& rhv)
  132. {
  133. return startOffset < rhv->endOffset();
  134. }
  135. static bool compareByStart(const RawPtrWillBeMember<DocumentMarker>& lhv, const RawPtrWillBeMember<DocumentMarker>& rhv)
  136. {
  137. return lhv->startOffset() < rhv->startOffset();
  138. }
  139. static bool doesNotOverlap(const OwnPtrWillBeMember<RenderedDocumentMarker>& lhv, const DocumentMarker* rhv)
  140. {
  141. return lhv->endOffset() < rhv->startOffset();
  142. }
  143. static bool doesNotInclude(const OwnPtrWillBeMember<RenderedDocumentMarker>& marker, size_t startOffset)
  144. {
  145. return marker->endOffset() < startOffset;
  146. }
  147. static bool updateMarkerRenderedRect(Node* node, RenderedDocumentMarker& marker)
  148. {
  149. RefPtrWillBeRawPtr<Range> range = Range::create(node->document());
  150. // The offsets of the marker may be out-dated, so check for exceptions.
  151. TrackExceptionState exceptionState;
  152. range->setStart(node, marker.startOffset(), exceptionState);
  153. if (!exceptionState.hadException())
  154. range->setEnd(node, marker.endOffset(), IGNORE_EXCEPTION);
  155. if (exceptionState.hadException())
  156. return marker.invalidateRenderedRect();
  157. return marker.setRenderedRect(LayoutRect(range->boundingBox()));
  158. }
  159. // Markers are stored in order sorted by their start offset.
  160. // Markers of the same type do not overlap each other.
  161. void DocumentMarkerController::addMarker(Node* node, const DocumentMarker& newMarker)
  162. {
  163. ASSERT(newMarker.endOffset() >= newMarker.startOffset());
  164. if (newMarker.endOffset() == newMarker.startOffset())
  165. return;
  166. m_possiblyExistingMarkerTypes.add(newMarker.type());
  167. OwnPtrWillBeMember<MarkerLists>& markers = m_markers.add(node, nullptr).storedValue->value;
  168. if (!markers) {
  169. markers = adoptPtrWillBeNoop(new MarkerLists);
  170. markers->grow(DocumentMarker::MarkerTypeIndexesCount);
  171. }
  172. DocumentMarker::MarkerTypeIndex markerListIndex = MarkerTypeToMarkerIndex(newMarker.type());
  173. if (!markers->at(markerListIndex)) {
  174. markers->insert(markerListIndex, adoptPtrWillBeNoop(new MarkerList));
  175. }
  176. OwnPtrWillBeMember<MarkerList>& list = markers->at(markerListIndex);
  177. OwnPtrWillBeRawPtr<RenderedDocumentMarker> newRenderedMarker = RenderedDocumentMarker::create(newMarker);
  178. updateMarkerRenderedRect(node, *newRenderedMarker);
  179. if (list->isEmpty() || list->last()->endOffset() < newMarker.startOffset()) {
  180. list->append(newRenderedMarker.release());
  181. } else {
  182. if (newMarker.type() != DocumentMarker::TextMatch && newMarker.type() != DocumentMarker::Composition) {
  183. mergeOverlapping(list.get(), newRenderedMarker.release());
  184. } else {
  185. MarkerList::iterator pos = std::lower_bound(list->begin(), list->end(), &newMarker, startsFurther);
  186. list->insert(pos - list->begin(), newRenderedMarker.release());
  187. }
  188. }
  189. // repaint the affected node
  190. if (node->layoutObject())
  191. node->layoutObject()->setShouldDoFullPaintInvalidation();
  192. }
  193. void DocumentMarkerController::mergeOverlapping(MarkerList* list, PassOwnPtrWillBeRawPtr<RenderedDocumentMarker> toInsert)
  194. {
  195. MarkerList::iterator firstOverlapping = std::lower_bound(list->begin(), list->end(), toInsert.get(), doesNotOverlap);
  196. size_t index = firstOverlapping - list->begin();
  197. list->insert(index, toInsert);
  198. MarkerList::iterator inserted = list->begin() + index;
  199. firstOverlapping = inserted + 1;
  200. for (MarkerList::iterator i = firstOverlapping; i != list->end() && (*i)->startOffset() <= (*inserted)->endOffset(); ) {
  201. (*inserted)->setStartOffset(std::min((*inserted)->startOffset(), (*i)->startOffset()));
  202. (*inserted)->setEndOffset(std::max((*inserted)->endOffset(), (*i)->endOffset()));
  203. list->remove(i - list->begin());
  204. }
  205. }
  206. // copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
  207. // useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
  208. void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
  209. {
  210. if (length <= 0)
  211. return;
  212. if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
  213. return;
  214. ASSERT(!m_markers.isEmpty());
  215. MarkerLists* markers = m_markers.get(srcNode);
  216. if (!markers)
  217. return;
  218. bool docDirty = false;
  219. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  220. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  221. if (!list)
  222. continue;
  223. unsigned endOffset = startOffset + length - 1;
  224. MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, doesNotInclude);
  225. for (MarkerList::iterator i = startPos; i != list->end(); ++i) {
  226. DocumentMarker* marker = i->get();
  227. // stop if we are now past the specified range
  228. if (marker->startOffset() > endOffset)
  229. break;
  230. // pin the marker to the specified range and apply the shift delta
  231. docDirty = true;
  232. if (marker->startOffset() < startOffset)
  233. marker->setStartOffset(startOffset);
  234. if (marker->endOffset() > endOffset)
  235. marker->setEndOffset(endOffset);
  236. marker->shiftOffsets(delta);
  237. addMarker(dstNode, *marker);
  238. }
  239. }
  240. // repaint the affected node
  241. if (docDirty && dstNode->layoutObject())
  242. dstNode->layoutObject()->setShouldDoFullPaintInvalidation();
  243. }
  244. void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerTypes markerTypes, RemovePartiallyOverlappingMarkerOrNot shouldRemovePartiallyOverlappingMarker)
  245. {
  246. if (length <= 0)
  247. return;
  248. if (!possiblyHasMarkers(markerTypes))
  249. return;
  250. ASSERT(!(m_markers.isEmpty()));
  251. MarkerLists* markers = m_markers.get(node);
  252. if (!markers)
  253. return;
  254. bool docDirty = false;
  255. size_t emptyListsCount = 0;
  256. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  257. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  258. if (!list || list->isEmpty()) {
  259. if (list.get() && list->isEmpty())
  260. list.clear();
  261. ++emptyListsCount;
  262. continue;
  263. }
  264. if (!markerTypes.contains((*list->begin())->type()))
  265. continue;
  266. unsigned endOffset = startOffset + length;
  267. MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
  268. for (MarkerList::iterator i = startPos; i != list->end(); ) {
  269. DocumentMarker marker(*i->get());
  270. // markers are returned in order, so stop if we are now past the specified range
  271. if (marker.startOffset() >= endOffset)
  272. break;
  273. // at this point we know that marker and target intersect in some way
  274. docDirty = true;
  275. // pitch the old marker
  276. list->remove(i - list->begin());
  277. if (shouldRemovePartiallyOverlappingMarker) {
  278. // Stop here. Don't add resulting slices back.
  279. continue;
  280. }
  281. // add either of the resulting slices that are left after removing target
  282. if (startOffset > marker.startOffset()) {
  283. DocumentMarker newLeft = marker;
  284. newLeft.setEndOffset(startOffset);
  285. size_t insertIndex = i - list->begin();
  286. list->insert(insertIndex, RenderedDocumentMarker::create(newLeft));
  287. // Move to the marker after the inserted one.
  288. i = list->begin() + insertIndex + 1;
  289. }
  290. if (marker.endOffset() > endOffset) {
  291. DocumentMarker newRight = marker;
  292. newRight.setStartOffset(endOffset);
  293. size_t insertIndex = i - list->begin();
  294. list->insert(insertIndex, RenderedDocumentMarker::create(newRight));
  295. // Move to the marker after the inserted one.
  296. i = list->begin() + insertIndex + 1;
  297. }
  298. }
  299. if (list->isEmpty()) {
  300. list.clear();
  301. ++emptyListsCount;
  302. }
  303. }
  304. if (emptyListsCount == DocumentMarker::MarkerTypeIndexesCount) {
  305. m_markers.remove(node);
  306. if (m_markers.isEmpty())
  307. m_possiblyExistingMarkerTypes = 0;
  308. }
  309. // repaint the affected node
  310. if (docDirty && node->layoutObject())
  311. node->layoutObject()->setShouldDoFullPaintInvalidation();
  312. }
  313. DocumentMarker* DocumentMarkerController::markerContainingPoint(const LayoutPoint& point, DocumentMarker::MarkerType markerType)
  314. {
  315. if (!possiblyHasMarkers(markerType))
  316. return 0;
  317. ASSERT(!(m_markers.isEmpty()));
  318. // outer loop: process each node that contains any markers
  319. MarkerMap::iterator end = m_markers.end();
  320. for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
  321. // inner loop; process each marker in this node
  322. MarkerLists* markers = nodeIterator->value.get();
  323. OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(markerType)];
  324. unsigned markerCount = list.get() ? list->size() : 0;
  325. for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
  326. RenderedDocumentMarker* marker = list->at(markerIndex).get();
  327. if (marker->contains(point))
  328. return marker;
  329. }
  330. }
  331. return 0;
  332. }
  333. DocumentMarkerVector DocumentMarkerController::markersFor(Node* node, DocumentMarker::MarkerTypes markerTypes)
  334. {
  335. DocumentMarkerVector result;
  336. MarkerLists* markers = m_markers.get(node);
  337. if (!markers)
  338. return result;
  339. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  340. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  341. if (!list || list->isEmpty() || !markerTypes.contains((*list->begin())->type()))
  342. continue;
  343. for (size_t i = 0; i < list->size(); ++i)
  344. result.append(list->at(i).get());
  345. }
  346. std::sort(result.begin(), result.end(), compareByStart);
  347. return result;
  348. }
  349. DocumentMarkerVector DocumentMarkerController::markers()
  350. {
  351. DocumentMarkerVector result;
  352. for (MarkerMap::iterator i = m_markers.begin(); i != m_markers.end(); ++i) {
  353. MarkerLists* markers = i->value.get();
  354. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  355. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  356. for (size_t j = 0; list.get() && j < list->size(); ++j)
  357. result.append(list->at(j).get());
  358. }
  359. }
  360. std::sort(result.begin(), result.end(), compareByStart);
  361. return result;
  362. }
  363. DocumentMarkerVector DocumentMarkerController::markersInRange(const EphemeralRange& range, DocumentMarker::MarkerTypes markerTypes)
  364. {
  365. if (!possiblyHasMarkers(markerTypes))
  366. return DocumentMarkerVector();
  367. DocumentMarkerVector foundMarkers;
  368. Node* startContainer = range.startPosition().computeContainerNode();
  369. ASSERT(startContainer);
  370. unsigned startOffset = static_cast<unsigned>(range.startPosition().computeOffsetInContainerNode());
  371. Node* endContainer = range.endPosition().computeContainerNode();
  372. ASSERT(endContainer);
  373. unsigned endOffset = static_cast<unsigned>(range.endPosition().computeOffsetInContainerNode());
  374. Node* pastLastNode = range.endPosition().nodeAsRangePastLastNode();
  375. for (Node* node = range.startPosition().nodeAsRangeFirstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
  376. for (DocumentMarker* marker : markersFor(node)) {
  377. if (!markerTypes.contains(marker->type()))
  378. continue;
  379. if (node == startContainer && marker->endOffset() <= startOffset)
  380. continue;
  381. if (node == endContainer && marker->startOffset() >= endOffset)
  382. continue;
  383. foundMarkers.append(marker);
  384. }
  385. }
  386. return foundMarkers;
  387. }
  388. Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
  389. {
  390. Vector<IntRect> result;
  391. if (!possiblyHasMarkers(markerType))
  392. return result;
  393. ASSERT(!(m_markers.isEmpty()));
  394. // outer loop: process each node
  395. MarkerMap::iterator end = m_markers.end();
  396. for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
  397. // inner loop; process each marker in this node
  398. MarkerLists* markers = nodeIterator->value.get();
  399. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  400. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  401. if (!list || list->isEmpty() || (*list->begin())->type() != markerType)
  402. continue;
  403. for (unsigned markerIndex = 0; markerIndex < list->size(); ++markerIndex) {
  404. RenderedDocumentMarker* marker = list->at(markerIndex).get();
  405. if (!marker->isRendered())
  406. continue;
  407. result.append(marker->renderedRect());
  408. }
  409. }
  410. }
  411. return result;
  412. }
  413. static void invalidatePaintForTickmarks(const Node& node)
  414. {
  415. if (FrameView* frameView = node.document().view())
  416. frameView->invalidatePaintForTickmarks();
  417. }
  418. void DocumentMarkerController::updateRenderedRectsForMarkers()
  419. {
  420. for (auto& nodeMarkers : m_markers) {
  421. const Node* node = nodeMarkers.key;
  422. for (auto& markerList : *nodeMarkers.value) {
  423. if (!markerList)
  424. continue;
  425. bool markersChanged = false;
  426. for (auto& marker : *markerList)
  427. markersChanged |= updateMarkerRenderedRect(const_cast<Node*>(node), *marker);
  428. if (markersChanged && markerList->first()->type() == DocumentMarker::TextMatch)
  429. invalidatePaintForTickmarks(*node);
  430. }
  431. }
  432. }
  433. DEFINE_TRACE(DocumentMarkerController)
  434. {
  435. #if ENABLE(OILPAN)
  436. visitor->trace(m_markers);
  437. #endif
  438. }
  439. void DocumentMarkerController::removeMarkers(Node* node, DocumentMarker::MarkerTypes markerTypes)
  440. {
  441. if (!possiblyHasMarkers(markerTypes))
  442. return;
  443. ASSERT(!m_markers.isEmpty());
  444. MarkerMap::iterator iterator = m_markers.find(node);
  445. if (iterator != m_markers.end())
  446. removeMarkersFromList(iterator, markerTypes);
  447. }
  448. void DocumentMarkerController::removeMarkers(const MarkerRemoverPredicate& shouldRemoveMarker)
  449. {
  450. for (auto& nodeMarkers : m_markers) {
  451. const Node& node = *nodeMarkers.key;
  452. if (!node.isTextNode()) // MarkerRemoverPredicate requires a Text node.
  453. continue;
  454. MarkerLists& markers = *nodeMarkers.value;
  455. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  456. OwnPtrWillBeMember<MarkerList>& list = markers[markerListIndex];
  457. if (!list)
  458. continue;
  459. bool removedMarkers = false;
  460. for (size_t j = list->size(); j > 0; --j) {
  461. if (shouldRemoveMarker(*list->at(j - 1), static_cast<const Text&>(node))) {
  462. list->remove(j - 1);
  463. removedMarkers = true;
  464. }
  465. }
  466. if (removedMarkers && markerListIndex == DocumentMarker::TextMatchMarkerIndex)
  467. invalidatePaintForTickmarks(node);
  468. }
  469. }
  470. }
  471. void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerTypes)
  472. {
  473. if (!possiblyHasMarkers(markerTypes))
  474. return;
  475. ASSERT(!m_markers.isEmpty());
  476. Vector<const Node*> nodesWithMarkers;
  477. copyKeysToVector(m_markers, nodesWithMarkers);
  478. unsigned size = nodesWithMarkers.size();
  479. for (unsigned i = 0; i < size; ++i) {
  480. MarkerMap::iterator iterator = m_markers.find(nodesWithMarkers[i]);
  481. if (iterator != m_markers.end())
  482. removeMarkersFromList(iterator, markerTypes);
  483. }
  484. m_possiblyExistingMarkerTypes.remove(markerTypes);
  485. }
  486. void DocumentMarkerController::removeMarkersFromList(MarkerMap::iterator iterator, DocumentMarker::MarkerTypes markerTypes)
  487. {
  488. bool needsRepainting = false;
  489. bool nodeCanBeRemoved;
  490. size_t emptyListsCount = 0;
  491. if (markerTypes == DocumentMarker::AllMarkers()) {
  492. needsRepainting = true;
  493. nodeCanBeRemoved = true;
  494. } else {
  495. MarkerLists* markers = iterator->value.get();
  496. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  497. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  498. if (!list || list->isEmpty()) {
  499. if (list.get() && list->isEmpty())
  500. list.clear();
  501. ++emptyListsCount;
  502. continue;
  503. }
  504. if (markerTypes.contains((*list->begin())->type())) {
  505. list->clear();
  506. list.clear();
  507. ++emptyListsCount;
  508. needsRepainting = true;
  509. }
  510. }
  511. nodeCanBeRemoved = emptyListsCount == DocumentMarker::MarkerTypeIndexesCount;
  512. }
  513. if (needsRepainting) {
  514. const Node& node = *iterator->key;
  515. if (LayoutObject* layoutObject = node.layoutObject())
  516. layoutObject->setShouldDoFullPaintInvalidation();
  517. invalidatePaintForTickmarks(node);
  518. }
  519. if (nodeCanBeRemoved) {
  520. m_markers.remove(iterator);
  521. if (m_markers.isEmpty())
  522. m_possiblyExistingMarkerTypes = 0;
  523. }
  524. }
  525. void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes)
  526. {
  527. if (!possiblyHasMarkers(markerTypes))
  528. return;
  529. ASSERT(!m_markers.isEmpty());
  530. // outer loop: process each markered node in the document
  531. MarkerMap::iterator end = m_markers.end();
  532. for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
  533. const Node* node = i->key;
  534. // inner loop: process each marker in the current node
  535. MarkerLists* markers = i->value.get();
  536. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  537. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  538. if (!list || list->isEmpty() || !markerTypes.contains((*list->begin())->type()))
  539. continue;
  540. // cause the node to be redrawn
  541. if (LayoutObject* layoutObject = node->layoutObject()) {
  542. layoutObject->setShouldDoFullPaintInvalidation();
  543. break;
  544. }
  545. }
  546. }
  547. }
  548. void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta)
  549. {
  550. if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
  551. return;
  552. ASSERT(!m_markers.isEmpty());
  553. MarkerLists* markers = m_markers.get(node);
  554. if (!markers)
  555. return;
  556. bool docDirty = false;
  557. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  558. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  559. if (!list)
  560. continue;
  561. MarkerList::iterator startPos = std::lower_bound(list->begin(), list->end(), startOffset, startsAfter);
  562. for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) {
  563. #if ENABLE(ASSERT)
  564. int startOffset = (*marker)->startOffset();
  565. ASSERT(startOffset + delta >= 0);
  566. #endif
  567. (*marker)->shiftOffsets(delta);
  568. docDirty = true;
  569. updateMarkerRenderedRect(node, **marker);
  570. }
  571. }
  572. // repaint the affected node
  573. if (docDirty && node->layoutObject())
  574. node->layoutObject()->setShouldDoFullPaintInvalidation();
  575. }
  576. void DocumentMarkerController::setMarkersActive(Range* range, bool active)
  577. {
  578. if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
  579. return;
  580. ASSERT(!m_markers.isEmpty());
  581. Node* startContainer = range->startContainer();
  582. Node* endContainer = range->endContainer();
  583. Node* pastLastNode = range->pastLastNode();
  584. for (Node* node = range->firstNode(); node != pastLastNode; node = NodeTraversal::next(*node)) {
  585. int startOffset = node == startContainer ? range->startOffset() : 0;
  586. int endOffset = node == endContainer ? range->endOffset() : INT_MAX;
  587. setMarkersActive(node, startOffset, endOffset, active);
  588. }
  589. }
  590. void DocumentMarkerController::setMarkersActive(Node* node, unsigned startOffset, unsigned endOffset, bool active)
  591. {
  592. MarkerLists* markers = m_markers.get(node);
  593. if (!markers)
  594. return;
  595. bool docDirty = false;
  596. OwnPtrWillBeMember<MarkerList>& list = (*markers)[MarkerTypeToMarkerIndex(DocumentMarker::TextMatch)];
  597. if (!list)
  598. return;
  599. MarkerList::iterator startPos = std::upper_bound(list->begin(), list->end(), startOffset, endsBefore);
  600. for (MarkerList::iterator marker = startPos; marker != list->end(); ++marker) {
  601. // Markers are returned in order, so stop if we are now past the specified range.
  602. if ((*marker)->startOffset() >= endOffset)
  603. break;
  604. (*marker)->setActiveMatch(active);
  605. docDirty = true;
  606. }
  607. // repaint the affected node
  608. if (docDirty && node->layoutObject())
  609. node->layoutObject()->setShouldDoFullPaintInvalidation();
  610. }
  611. #ifndef NDEBUG
  612. void DocumentMarkerController::showMarkers() const
  613. {
  614. fprintf(stderr, "%d nodes have markers:\n", m_markers.size());
  615. MarkerMap::const_iterator end = m_markers.end();
  616. for (MarkerMap::const_iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
  617. const Node* node = nodeIterator->key;
  618. fprintf(stderr, "%p", node);
  619. MarkerLists* markers = m_markers.get(node);
  620. for (size_t markerListIndex = 0; markerListIndex < DocumentMarker::MarkerTypeIndexesCount; ++markerListIndex) {
  621. OwnPtrWillBeMember<MarkerList>& list = (*markers)[markerListIndex];
  622. for (unsigned markerIndex = 0; list.get() && markerIndex < list->size(); ++markerIndex) {
  623. DocumentMarker* marker = list->at(markerIndex).get();
  624. fprintf(stderr, " %d:[%d:%d](%d)", marker->type(), marker->startOffset(), marker->endOffset(), marker->activeMatch());
  625. }
  626. }
  627. fprintf(stderr, "\n");
  628. }
  629. }
  630. #endif
  631. } // namespace blink
  632. #ifndef NDEBUG
  633. void showDocumentMarkers(const blink::DocumentMarkerController* controller)
  634. {
  635. if (controller)
  636. controller->showMarkers();
  637. }
  638. #endif