1
// Copyright 2011 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
6
// * Redistributions of source code must retain the above copyright
7
// notice, this list of conditions and the following disclaimer.
8
// * Redistributions in binary form must reproduce the above
9
// copyright notice, this list of conditions and the following
10
// disclaimer in the documentation and/or other materials provided
11
// with the distribution.
12
// * Neither the name of Google Inc. nor the names of its
13
// contributors may be used to endorse or promote products derived
14
// from this software without specific prior written permission.
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
#include "src/extensions/experimental/break-iterator.h"
32
#include "unicode/brkiter.h"
33
#include "unicode/locid.h"
34
#include "unicode/rbbi.h"
39
v8::Persistent<v8::FunctionTemplate> BreakIterator::break_iterator_template_;
41
icu::BreakIterator* BreakIterator::UnpackBreakIterator(
42
v8::Handle<v8::Object> obj) {
43
if (break_iterator_template_->HasInstance(obj)) {
44
return static_cast<icu::BreakIterator*>(
45
obj->GetPointerFromInternalField(0));
51
icu::UnicodeString* BreakIterator::ResetAdoptedText(
52
v8::Handle<v8::Object> obj, v8::Handle<v8::Value> value) {
53
// Get the previous value from the internal field.
54
icu::UnicodeString* text = static_cast<icu::UnicodeString*>(
55
obj->GetPointerFromInternalField(1));
58
// Assign new value to the internal pointer.
59
v8::String::Value text_value(value);
60
text = new icu::UnicodeString(
61
reinterpret_cast<const UChar*>(*text_value), text_value.length());
62
obj->SetPointerInInternalField(1, text);
64
// Return new unicode string pointer.
68
void BreakIterator::DeleteBreakIterator(v8::Persistent<v8::Value> object,
70
v8::Persistent<v8::Object> persistent_object =
71
v8::Persistent<v8::Object>::Cast(object);
73
// First delete the hidden C++ object.
74
// Unpacking should never return NULL here. That would only happen if
75
// this method is used as the weak callback for persistent handles not
76
// pointing to a break iterator.
77
delete UnpackBreakIterator(persistent_object);
79
delete static_cast<icu::UnicodeString*>(
80
persistent_object->GetPointerFromInternalField(1));
82
// Then dispose of the persistent handle to JS object.
83
persistent_object.Dispose();
86
// Throws a JavaScript exception.
87
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
88
// Returns undefined, and schedules an exception to be thrown.
89
return v8::ThrowException(v8::Exception::Error(
90
v8::String::New("BreakIterator method called on an object "
91
"that is not a BreakIterator.")));
94
v8::Handle<v8::Value> BreakIterator::BreakIteratorAdoptText(
95
const v8::Arguments& args) {
96
if (args.Length() != 1 || !args[0]->IsString()) {
97
return v8::ThrowException(v8::Exception::SyntaxError(
98
v8::String::New("Text input is required.")));
101
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
102
if (!break_iterator) {
103
return ThrowUnexpectedObjectError();
106
break_iterator->setText(*ResetAdoptedText(args.Holder(), args[0]));
108
return v8::Undefined();
111
v8::Handle<v8::Value> BreakIterator::BreakIteratorFirst(
112
const v8::Arguments& args) {
113
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
114
if (!break_iterator) {
115
return ThrowUnexpectedObjectError();
118
return v8::Int32::New(break_iterator->first());
121
v8::Handle<v8::Value> BreakIterator::BreakIteratorNext(
122
const v8::Arguments& args) {
123
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
124
if (!break_iterator) {
125
return ThrowUnexpectedObjectError();
128
return v8::Int32::New(break_iterator->next());
131
v8::Handle<v8::Value> BreakIterator::BreakIteratorCurrent(
132
const v8::Arguments& args) {
133
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
134
if (!break_iterator) {
135
return ThrowUnexpectedObjectError();
138
return v8::Int32::New(break_iterator->current());
141
v8::Handle<v8::Value> BreakIterator::BreakIteratorBreakType(
142
const v8::Arguments& args) {
143
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
144
if (!break_iterator) {
145
return ThrowUnexpectedObjectError();
148
// TODO(cira): Remove cast once ICU fixes base BreakIterator class.
149
icu::RuleBasedBreakIterator* rule_based_iterator =
150
static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
151
int32_t status = rule_based_iterator->getRuleStatus();
152
// Keep return values in sync with JavaScript BreakType enum.
153
if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
154
return v8::Int32::New(UBRK_WORD_NONE);
155
} else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
156
return v8::Int32::New(UBRK_WORD_NUMBER);
157
} else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
158
return v8::Int32::New(UBRK_WORD_LETTER);
159
} else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
160
return v8::Int32::New(UBRK_WORD_KANA);
161
} else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
162
return v8::Int32::New(UBRK_WORD_IDEO);
164
return v8::Int32::New(-1);
168
v8::Handle<v8::Value> BreakIterator::JSBreakIterator(
169
const v8::Arguments& args) {
170
v8::HandleScope handle_scope;
172
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
173
return v8::ThrowException(v8::Exception::SyntaxError(
174
v8::String::New("Locale and iterator type are required.")));
177
v8::String::Utf8Value locale(args[0]);
178
icu::Locale icu_locale(*locale);
180
UErrorCode status = U_ZERO_ERROR;
181
icu::BreakIterator* break_iterator = NULL;
182
v8::String::Utf8Value type(args[1]);
183
if (!strcmp(*type, "character")) {
185
icu::BreakIterator::createCharacterInstance(icu_locale, status);
186
} else if (!strcmp(*type, "word")) {
188
icu::BreakIterator::createWordInstance(icu_locale, status);
189
} else if (!strcmp(*type, "sentence")) {
191
icu::BreakIterator::createSentenceInstance(icu_locale, status);
192
} else if (!strcmp(*type, "line")) {
194
icu::BreakIterator::createLineInstance(icu_locale, status);
196
return v8::ThrowException(v8::Exception::SyntaxError(
197
v8::String::New("Invalid iterator type.")));
200
if (U_FAILURE(status)) {
201
delete break_iterator;
202
return v8::ThrowException(v8::Exception::Error(
203
v8::String::New("Failed to create break iterator.")));
206
if (break_iterator_template_.IsEmpty()) {
207
v8::Local<v8::FunctionTemplate> raw_template(v8::FunctionTemplate::New());
209
raw_template->SetClassName(v8::String::New("v8Locale.v8BreakIterator"));
211
// Define internal field count on instance template.
212
v8::Local<v8::ObjectTemplate> object_template =
213
raw_template->InstanceTemplate();
215
// Set aside internal fields for icu break iterator and adopted text.
216
object_template->SetInternalFieldCount(2);
218
// Define all of the prototype methods on prototype template.
219
v8::Local<v8::ObjectTemplate> proto = raw_template->PrototypeTemplate();
220
proto->Set(v8::String::New("adoptText"),
221
v8::FunctionTemplate::New(BreakIteratorAdoptText));
222
proto->Set(v8::String::New("first"),
223
v8::FunctionTemplate::New(BreakIteratorFirst));
224
proto->Set(v8::String::New("next"),
225
v8::FunctionTemplate::New(BreakIteratorNext));
226
proto->Set(v8::String::New("current"),
227
v8::FunctionTemplate::New(BreakIteratorCurrent));
228
proto->Set(v8::String::New("breakType"),
229
v8::FunctionTemplate::New(BreakIteratorBreakType));
231
break_iterator_template_ =
232
v8::Persistent<v8::FunctionTemplate>::New(raw_template);
235
// Create an empty object wrapper.
236
v8::Local<v8::Object> local_object =
237
break_iterator_template_->GetFunction()->NewInstance();
238
v8::Persistent<v8::Object> wrapper =
239
v8::Persistent<v8::Object>::New(local_object);
241
// Set break iterator as internal field of the resulting JS object.
242
wrapper->SetPointerInInternalField(0, break_iterator);
243
// Make sure that the pointer to adopted text is NULL.
244
wrapper->SetPointerInInternalField(1, NULL);
246
// Make object handle weak so we can delete iterator once GC kicks in.
247
wrapper.MakeWeak(NULL, DeleteBreakIterator);
252
} } // namespace v8::internal