1 | /* |
2 | * Copyright (C) 2000 Lars Knoll (knoll@kde.org) |
3 | * Copyright (C) 2003-2017 Apple Inc. All right reserved. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | * |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include "BidiContext.h" |
24 | |
25 | #include <wtf/Vector.h> |
26 | |
27 | namespace WebCore { |
28 | |
29 | struct SameSizeAsBidiContext : public RefCounted<SameSizeAsBidiContext> { |
30 | uint32_t bitfields : 16; |
31 | void* parent; |
32 | }; |
33 | |
34 | COMPILE_ASSERT(sizeof(BidiContext) == sizeof(SameSizeAsBidiContext), BidiContext_should_stay_small); |
35 | |
36 | inline BidiContext::BidiContext(unsigned char level, UCharDirection direction, bool override, BidiEmbeddingSource source, BidiContext* parent) |
37 | : m_level(level) |
38 | , m_direction(direction) |
39 | , m_override(override) |
40 | , m_source(source) |
41 | , m_parent(parent) |
42 | { |
43 | } |
44 | |
45 | inline Ref<BidiContext> BidiContext::createUncached(unsigned char level, UCharDirection direction, bool override, BidiEmbeddingSource source, BidiContext* parent) |
46 | { |
47 | return adoptRef(*new BidiContext(level, direction, override, source, parent)); |
48 | } |
49 | |
50 | Ref<BidiContext> BidiContext::create(unsigned char level, UCharDirection direction, bool override, BidiEmbeddingSource source, BidiContext* parent) |
51 | { |
52 | ASSERT(direction == (level % 2 ? U_RIGHT_TO_LEFT : U_LEFT_TO_RIGHT)); |
53 | |
54 | if (parent) |
55 | return createUncached(level, direction, override, source, parent); |
56 | |
57 | ASSERT(level <= 1); |
58 | if (!level) { |
59 | if (!override) { |
60 | static BidiContext& ltrContext = createUncached(0, U_LEFT_TO_RIGHT, false, FromStyleOrDOM, 0).leakRef(); |
61 | return ltrContext; |
62 | } |
63 | |
64 | static BidiContext& ltrOverrideContext = createUncached(0, U_LEFT_TO_RIGHT, true, FromStyleOrDOM, 0).leakRef(); |
65 | return ltrOverrideContext; |
66 | } |
67 | |
68 | if (!override) { |
69 | static BidiContext& rtlContext = createUncached(1, U_RIGHT_TO_LEFT, false, FromStyleOrDOM, 0).leakRef(); |
70 | return rtlContext; |
71 | } |
72 | |
73 | static BidiContext& rtlOverrideContext = createUncached(1, U_RIGHT_TO_LEFT, true, FromStyleOrDOM, 0).leakRef(); |
74 | return rtlOverrideContext; |
75 | } |
76 | |
77 | static inline Ref<BidiContext> copyContextAndRebaselineLevel(BidiContext& context, BidiContext* parent) |
78 | { |
79 | auto newLevel = parent ? parent->level() : 0; |
80 | if (context.dir() == U_RIGHT_TO_LEFT) |
81 | newLevel = nextGreaterOddLevel(newLevel); |
82 | else if (parent) |
83 | newLevel = nextGreaterEvenLevel(newLevel); |
84 | return BidiContext::create(newLevel, context.dir(), context.override(), context.source(), parent); |
85 | } |
86 | |
87 | // The BidiContext stack must be immutable -- they're re-used for re-layout after |
88 | // DOM modification/editing -- so we copy all the non-Unicode contexts, and |
89 | // recalculate their levels. |
90 | Ref<BidiContext> BidiContext::copyStackRemovingUnicodeEmbeddingContexts() |
91 | { |
92 | Vector<BidiContext*, 64> contexts; |
93 | for (auto* ancestor = this; ancestor; ancestor = ancestor->parent()) { |
94 | if (ancestor->source() != FromUnicode) |
95 | contexts.append(ancestor); |
96 | } |
97 | ASSERT(contexts.size()); |
98 | auto topContext = copyContextAndRebaselineLevel(*contexts.last(), nullptr); |
99 | for (unsigned i = contexts.size() - 1; i; --i) |
100 | topContext = copyContextAndRebaselineLevel(*contexts[i - 1], topContext.ptr()); |
101 | return topContext; |
102 | } |
103 | |
104 | bool operator==(const BidiContext& c1, const BidiContext& c2) |
105 | { |
106 | if (&c1 == &c2) |
107 | return true; |
108 | if (c1.level() != c2.level() || c1.override() != c2.override() || c1.dir() != c2.dir() || c1.source() != c2.source()) |
109 | return false; |
110 | if (!c1.parent()) |
111 | return !c2.parent(); |
112 | return c2.parent() && *c1.parent() == *c2.parent(); |
113 | } |
114 | |
115 | } // namespace WebCore |
116 | |