Split ICU UText providers out into their own files
[WebKit-https.git] / Source / WebCore / platform / text / icu / UTextProviderUTF16.cpp
1 /*
2  * Copyright (C) 2014 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 "UTextProviderUTF16.h"
28
29 #include "UTextProvider.h"
30
31 namespace WebCore {
32
33 static inline UTextProviderContext textUTF16GetCurrentContext(const UText* text)
34 {
35     if (!text->chunkContents)
36         return UTextProviderContext::NoContext;
37     return text->chunkContents == text->p ? UTextProviderContext::PrimaryContext : UTextProviderContext::PriorContext;
38 }
39
40 static void textUTF16MoveInPrimaryContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward)
41 {
42     ASSERT(text->chunkContents == text->p);
43     ASSERT_UNUSED(forward, forward ? nativeIndex >= text->b : nativeIndex > text->b);
44     ASSERT_UNUSED(forward, forward ? nativeIndex < nativeLength : nativeIndex <= nativeLength);
45     text->chunkNativeStart = text->b;
46     text->chunkNativeLimit = nativeLength;
47     int64_t length = text->chunkNativeLimit - text->chunkNativeStart;
48     // Ensure chunk length is well defined if computed length exceeds int32_t range.
49     ASSERT(length < std::numeric_limits<int32_t>::max());
50     text->chunkLength = length < std::numeric_limits<int32_t>::max() ? static_cast<int32_t>(length) : 0;
51     text->nativeIndexingLimit = text->chunkLength;
52     int64_t offset = nativeIndex - text->chunkNativeStart;
53     // Ensure chunk offset is well defined if computed offset exceeds int32_t range or chunk length.
54     ASSERT(offset < std::numeric_limits<int32_t>::max());
55     text->chunkOffset = std::min(offset < std::numeric_limits<int32_t>::max() ? static_cast<int32_t>(offset) : 0, text->chunkLength);
56 }
57
58 static void textUTF16SwitchToPrimaryContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward)
59 {
60     ASSERT(!text->chunkContents || text->chunkContents == text->q);
61     text->chunkContents = static_cast<const UChar*>(text->p);
62     textUTF16MoveInPrimaryContext(text, nativeIndex, nativeLength, forward);
63 }
64
65 static void textUTF16MoveInPriorContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward)
66 {
67     ASSERT(text->chunkContents == text->q);
68     ASSERT(forward ? nativeIndex < text->b : nativeIndex <= text->b);
69     ASSERT_UNUSED(nativeLength, forward ? nativeIndex < nativeLength : nativeIndex <= nativeLength);
70     ASSERT_UNUSED(forward, forward ? nativeIndex < nativeLength : nativeIndex <= nativeLength);
71     text->chunkNativeStart = 0;
72     text->chunkNativeLimit = text->b;
73     text->chunkLength = text->b;
74     text->nativeIndexingLimit = text->chunkLength;
75     int64_t offset = nativeIndex - text->chunkNativeStart;
76     // Ensure chunk offset is well defined if computed offset exceeds int32_t range or chunk length.
77     ASSERT(offset < std::numeric_limits<int32_t>::max());
78     text->chunkOffset = std::min(offset < std::numeric_limits<int32_t>::max() ? static_cast<int32_t>(offset) : 0, text->chunkLength);
79 }
80
81 static void textUTF16SwitchToPriorContext(UText* text, int64_t nativeIndex, int64_t nativeLength, UBool forward)
82 {
83     ASSERT(!text->chunkContents || text->chunkContents == text->p);
84     text->chunkContents = static_cast<const UChar*>(text->q);
85     textUTF16MoveInPriorContext(text, nativeIndex, nativeLength, forward);
86 }
87
88 // -- Begin UTF-16 provider functions --
89
90 static UText* uTextUTF16Clone(UText*, const UText*, UBool, UErrorCode*);
91 static int64_t uTextUTF16NativeLength(UText*);
92 static UBool uTextUTF16Access(UText*, int64_t, UBool);
93 static int32_t uTextUTF16Extract(UText*, int64_t, int64_t, UChar*, int32_t, UErrorCode*);
94 static void uTextUTF16Close(UText*);
95
96 static UText* uTextUTF16Clone(UText* destination, const UText* source, UBool deep, UErrorCode* status)
97 {
98     return uTextCloneImpl(destination, source, deep, status);
99 }
100
101 static inline int64_t uTextUTF16NativeLength(UText* text)
102 {
103     return text->a + text->b;
104 }
105
106 static UBool uTextUTF16Access(UText* text, int64_t nativeIndex, UBool forward)
107 {
108     if (!text->context)
109         return FALSE;
110     int64_t nativeLength = uTextUTF16NativeLength(text);
111     UBool isAccessible;
112     if (uTextAccessInChunkOrOutOfRange(text, nativeIndex, nativeLength, forward, isAccessible))
113         return isAccessible;
114     nativeIndex = uTextAccessPinIndex(nativeIndex, nativeLength);
115     UTextProviderContext currentContext = textUTF16GetCurrentContext(text);
116     UTextProviderContext newContext = uTextProviderContext(text, nativeIndex, forward);
117     ASSERT(newContext != UTextProviderContext::NoContext);
118     if (newContext == currentContext) {
119         if (currentContext == UTextProviderContext::PrimaryContext)
120             textUTF16MoveInPrimaryContext(text, nativeIndex, nativeLength, forward);
121         else
122             textUTF16MoveInPriorContext(text, nativeIndex, nativeLength, forward);
123     } else if (newContext == UTextProviderContext::PrimaryContext)
124         textUTF16SwitchToPrimaryContext(text, nativeIndex, nativeLength, forward);
125     else {
126         ASSERT(newContext == UTextProviderContext::PriorContext);
127         textUTF16SwitchToPriorContext(text, nativeIndex, nativeLength, forward);
128     }
129     return TRUE;
130 }
131
132 static int32_t uTextUTF16Extract(UText*, int64_t, int64_t, UChar*, int32_t, UErrorCode* errorCode)
133 {
134     // In the present context, this text provider is used only with ICU functions
135     // that do not perform an extract operation.
136     ASSERT_NOT_REACHED();
137     *errorCode = U_UNSUPPORTED_ERROR;
138     return 0;
139 }
140
141 static void uTextUTF16Close(UText* text)
142 {
143     text->context = 0;
144 }
145
146 // -- End UTF-16 provider functions --
147
148 static const struct UTextFuncs textUTF16Funcs = {
149     sizeof(UTextFuncs),
150     0, 0, 0,
151     uTextUTF16Clone,
152     uTextUTF16NativeLength,
153     uTextUTF16Access,
154     uTextUTF16Extract,
155     0, 0, 0, 0,
156     uTextUTF16Close,
157     0, 0, 0,
158 };
159
160 UText* uTextOpenUTF16(UText* text, const UChar* string, unsigned length, const UChar* priorContext, int priorContextLength, UErrorCode* status)
161 {
162     if (U_FAILURE(*status))
163         return 0;
164     if (!string || length > static_cast<unsigned>(std::numeric_limits<int32_t>::max())) {
165         *status = U_ILLEGAL_ARGUMENT_ERROR;
166         return 0;
167     }
168     text = utext_setup(text, 0, status);
169     if (U_FAILURE(*status)) {
170         ASSERT(!text);
171         return 0;
172     }
173     uTextInitialize(text, &textUTF16Funcs, string, length, priorContext, priorContextLength);
174     return text;
175 }
176
177 } // namespace WebCore