1 | /* |
2 | * Copyright (C) 2017 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "MarkedText.h" |
28 | |
29 | #include <algorithm> |
30 | #include <wtf/HashSet.h> |
31 | |
32 | namespace WebCore { |
33 | |
34 | Vector<MarkedText> subdivide(const Vector<MarkedText>& markedTexts, OverlapStrategy overlapStrategy) |
35 | { |
36 | if (markedTexts.isEmpty()) |
37 | return { }; |
38 | |
39 | struct Offset { |
40 | enum Kind { Begin, End }; |
41 | Kind kind; |
42 | unsigned value; // Copy of markedText.startOffset/endOffset to avoid the need to branch based on kind. |
43 | const MarkedText* markedText; |
44 | }; |
45 | |
46 | // 1. Build table of all offsets. |
47 | Vector<Offset> offsets; |
48 | ASSERT(markedTexts.size() < std::numeric_limits<unsigned>::max() / 2); |
49 | unsigned numberOfMarkedTexts = markedTexts.size(); |
50 | unsigned numberOfOffsets = 2 * numberOfMarkedTexts; |
51 | offsets.reserveInitialCapacity(numberOfOffsets); |
52 | for (auto& markedText : markedTexts) { |
53 | offsets.uncheckedAppend({ Offset::Begin, markedText.startOffset, &markedText }); |
54 | offsets.uncheckedAppend({ Offset::End, markedText.endOffset, &markedText }); |
55 | } |
56 | |
57 | // 2. Sort offsets such that begin offsets are in paint order and end offsets are in reverse paint order. |
58 | std::sort(offsets.begin(), offsets.end(), [] (const Offset& a, const Offset& b) { |
59 | return a.value < b.value || (a.value == b.value && a.kind == b.kind && a.kind == Offset::Begin && a.markedText->type < b.markedText->type) |
60 | || (a.value == b.value && a.kind == b.kind && a.kind == Offset::End && a.markedText->type > b.markedText->type); |
61 | }); |
62 | |
63 | // 3. Compute intersection. |
64 | Vector<MarkedText> result; |
65 | result.reserveInitialCapacity(numberOfMarkedTexts); |
66 | HashSet<const MarkedText*> processedMarkedTexts; |
67 | unsigned offsetSoFar = offsets[0].value; |
68 | for (unsigned i = 1; i < numberOfOffsets; ++i) { |
69 | if (offsets[i].value > offsets[i - 1].value) { |
70 | if (overlapStrategy == OverlapStrategy::Frontmost) { |
71 | Optional<unsigned> frontmost; |
72 | for (unsigned j = 0; j < i; ++j) { |
73 | if (!processedMarkedTexts.contains(offsets[j].markedText) && (!frontmost || offsets[j].markedText->type > offsets[*frontmost].markedText->type)) |
74 | frontmost = j; |
75 | } |
76 | if (frontmost) |
77 | result.append({ offsetSoFar, offsets[i].value, offsets[*frontmost].markedText->type, offsets[*frontmost].markedText->marker }); |
78 | } else { |
79 | // The appended marked texts may not be in paint order. We will fix this up at the end of this function. |
80 | for (unsigned j = 0; j < i; ++j) { |
81 | if (!processedMarkedTexts.contains(offsets[j].markedText)) |
82 | result.append({ offsetSoFar, offsets[i].value, offsets[j].markedText->type, offsets[j].markedText->marker }); |
83 | } |
84 | } |
85 | offsetSoFar = offsets[i].value; |
86 | } |
87 | if (offsets[i].kind == Offset::End) |
88 | processedMarkedTexts.add(offsets[i].markedText); |
89 | } |
90 | // Fix up; sort the marked texts so that they are in paint order. |
91 | if (overlapStrategy == OverlapStrategy::None) |
92 | std::sort(result.begin(), result.end(), [] (const MarkedText& a, const MarkedText& b) { return a.startOffset < b.startOffset || (a.startOffset == b.startOffset && a.type < b.type); }); |
93 | return result; |
94 | } |
95 | |
96 | } |
97 | |
98 | |
99 | |