1 /*
2  * This file is part of the DOM implementation for WebCore.
3  *
4  * Copyright (C) 2006 Apple Computer, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_DOCUMENT_MARKER_H_
24 #define THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_DOCUMENT_MARKER_H_
25 
26 #include "base/optional.h"
27 #include "third_party/blink/renderer/core/core_export.h"
28 #include "third_party/blink/renderer/platform/graphics/color.h"
29 #include "third_party/blink/renderer/platform/heap/handle.h"
30 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
31 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
32 #include "third_party/blink/renderer/platform/wtf/vector_traits.h"
33 
34 namespace blink {
35 
36 // A range of a node within a document that is "marked", such as the range of a
37 // misspelled word. It optionally includes a description that could be displayed
38 // in the user interface.
39 class CORE_EXPORT DocumentMarker : public GarbageCollected<DocumentMarker> {
40  public:
41   enum MarkerTypeIndex {
42     kSpellingMarkerIndex = 0,
43     kGrammarMarkerIndex,
44     kTextMatchMarkerIndex,
45     kCompositionMarkerIndex,
46     kActiveSuggestionMarkerIndex,
47     kSuggestionMarkerIndex,
48     kTextFragmentMarkerIndex,
49     kMarkerTypeIndexesCount
50   };
51 
52   enum MarkerType {
53     kSpelling = 1 << kSpellingMarkerIndex,
54     kGrammar = 1 << kGrammarMarkerIndex,
55     kTextMatch = 1 << kTextMatchMarkerIndex,
56     kComposition = 1 << kCompositionMarkerIndex,
57     kActiveSuggestion = 1 << kActiveSuggestionMarkerIndex,
58     kSuggestion = 1 << kSuggestionMarkerIndex,
59     kTextFragment = 1 << kTextFragmentMarkerIndex,
60   };
61 
62   class MarkerTypesIterator
63       : public std::iterator<std::forward_iterator_tag, MarkerType> {
64    public:
MarkerTypesIterator(unsigned marker_types)65     explicit MarkerTypesIterator(unsigned marker_types)
66         : remaining_types_(marker_types) {}
67     MarkerTypesIterator(const MarkerTypesIterator& other) = default;
68 
69     bool operator==(const MarkerTypesIterator& other) {
70       return remaining_types_ == other.remaining_types_;
71     }
72     bool operator!=(const MarkerTypesIterator& other) {
73       return !operator==(other);
74     }
75 
76     MarkerTypesIterator& operator++() {
77       DCHECK(remaining_types_);
78       // Turn off least significant 1-bit (from Hacker's Delight 2-1)
79       // Example:
80       // 7: 7 & 6 = 6
81       // 6: 6 & 5 = 4
82       // 4: 4 & 3 = 0
83       remaining_types_ &= (remaining_types_ - 1);
84       return *this;
85     }
86 
87     MarkerType operator*() const {
88       DCHECK(remaining_types_);
89       // Isolate least significant 1-bit (from Hacker's Delight 2-1)
90       // Example:
91       // 7: 7 & -7 = 1
92       // 6: 6 & -6 = 2
93       // 4: 4 & -4 = 4
94       return static_cast<MarkerType>(remaining_types_ &
95                                      (~remaining_types_ + 1));
96     }
97 
98    private:
99     unsigned remaining_types_;
100   };
101 
102   class MarkerTypes {
103     DISALLOW_NEW();
104 
105    public:
mask_(mask)106     explicit MarkerTypes(unsigned mask = 0) : mask_(mask) {}
107 
All()108     static MarkerTypes All() {
109       return MarkerTypes((1 << kMarkerTypeIndexesCount) - 1);
110     }
111 
AllBut(const MarkerTypes & types)112     static MarkerTypes AllBut(const MarkerTypes& types) {
113       return MarkerTypes(All().mask_ & ~types.mask_);
114     }
115 
ActiveSuggestion()116     static MarkerTypes ActiveSuggestion() {
117       return MarkerTypes(kActiveSuggestion);
118     }
Composition()119     static MarkerTypes Composition() { return MarkerTypes(kComposition); }
Grammar()120     static MarkerTypes Grammar() { return MarkerTypes(kGrammar); }
Misspelling()121     static MarkerTypes Misspelling() {
122       return MarkerTypes(kSpelling | kGrammar);
123     }
Spelling()124     static MarkerTypes Spelling() { return MarkerTypes(kSpelling); }
TextMatch()125     static MarkerTypes TextMatch() { return MarkerTypes(kTextMatch); }
Suggestion()126     static MarkerTypes Suggestion() { return MarkerTypes(kSuggestion); }
TextFragment()127     static MarkerTypes TextFragment() { return MarkerTypes(kTextFragment); }
128 
Contains(MarkerType type)129     bool Contains(MarkerType type) const { return mask_ & type; }
Intersects(const MarkerTypes & types)130     bool Intersects(const MarkerTypes& types) const {
131       return (mask_ & types.mask_);
132     }
133     bool operator==(const MarkerTypes& other) const {
134       return mask_ == other.mask_;
135     }
136 
Add(const MarkerTypes & types)137     MarkerTypes Add(const MarkerTypes& types) const {
138       return MarkerTypes(mask_ | types.mask_);
139     }
140 
begin()141     MarkerTypesIterator begin() const { return MarkerTypesIterator(mask_); }
end()142     MarkerTypesIterator end() const { return MarkerTypesIterator(0); }
143 
144    private:
145     unsigned mask_;
146   };
147 
148   virtual ~DocumentMarker();
149 
150   virtual MarkerType GetType() const = 0;
StartOffset()151   unsigned StartOffset() const { return start_offset_; }
EndOffset()152   unsigned EndOffset() const { return end_offset_; }
153 
154   struct MarkerOffsets {
155     unsigned start_offset;
156     unsigned end_offset;
157   };
158 
159   base::Optional<MarkerOffsets> ComputeOffsetsAfterShift(
160       unsigned offset,
161       unsigned old_length,
162       unsigned new_length) const;
163 
164   // Offset modifications are done by DocumentMarkerController.
165   // Other classes should not call following setters.
SetStartOffset(unsigned offset)166   void SetStartOffset(unsigned offset) { start_offset_ = offset; }
SetEndOffset(unsigned offset)167   void SetEndOffset(unsigned offset) { end_offset_ = offset; }
168   void ShiftOffsets(int delta);
169 
Trace(Visitor * visitor)170   virtual void Trace(Visitor* visitor) const {}
171 
172  protected:
173   DocumentMarker(unsigned start_offset, unsigned end_offset);
174 
175  private:
176   unsigned start_offset_;
177   unsigned end_offset_;
178 
179   DISALLOW_COPY_AND_ASSIGN(DocumentMarker);
180 };
181 
182 using DocumentMarkerVector = HeapVector<Member<DocumentMarker>>;
183 
184 }  // namespace blink
185 
186 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EDITING_MARKERS_DOCUMENT_MARKER_H_
187