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
27namespace WebCore {
28
29struct SameSizeAsBidiContext : public RefCounted<SameSizeAsBidiContext> {
30 uint32_t bitfields : 16;
31 void* parent;
32};
33
34COMPILE_ASSERT(sizeof(BidiContext) == sizeof(SameSizeAsBidiContext), BidiContext_should_stay_small);
35
36inline 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
45inline 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
50Ref<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
77static 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.
90Ref<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
104bool 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