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 "extensions/experimental/break-iterator.h"
32
#include "unicode/brkiter.h"
33
#include "unicode/locid.h"
34
#include "unicode/rbbi.h"
38
v8::Persistent<v8::FunctionTemplate> BreakIterator::break_iterator_template_;
40
icu::BreakIterator* BreakIterator::UnpackBreakIterator(
41
v8::Handle<v8::Object> obj) {
42
if (break_iterator_template_->HasInstance(obj)) {
43
return static_cast<icu::BreakIterator*>(
44
obj->GetPointerFromInternalField(0));
50
icu::UnicodeString* BreakIterator::ResetAdoptedText(
51
v8::Handle<v8::Object> obj, v8::Handle<v8::Value> value) {
52
// Get the previous value from the internal field.
53
icu::UnicodeString* text = static_cast<icu::UnicodeString*>(
54
obj->GetPointerFromInternalField(1));
57
// Assign new value to the internal pointer.
58
v8::String::Value text_value(value);
59
text = new icu::UnicodeString(
60
reinterpret_cast<const UChar*>(*text_value), text_value.length());
61
obj->SetPointerInInternalField(1, text);
63
// Return new unicode string pointer.
67
void BreakIterator::DeleteBreakIterator(v8::Persistent<v8::Value> object,
69
v8::Persistent<v8::Object> persistent_object =
70
v8::Persistent<v8::Object>::Cast(object);
72
// First delete the hidden C++ object.
73
// Unpacking should never return NULL here. That would only happen if
74
// this method is used as the weak callback for persistent handles not
75
// pointing to a break iterator.
76
delete UnpackBreakIterator(persistent_object);
78
delete static_cast<icu::UnicodeString*>(
79
persistent_object->GetPointerFromInternalField(1));
81
// Then dispose of the persistent handle to JS object.
82
persistent_object.Dispose();
85
// Throws a JavaScript exception.
86
static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
87
// Returns undefined, and schedules an exception to be thrown.
88
return v8::ThrowException(v8::Exception::Error(
89
v8::String::New("BreakIterator method called on an object "
90
"that is not a BreakIterator.")));
93
v8::Handle<v8::Value> BreakIterator::BreakIteratorAdoptText(
94
const v8::Arguments& args) {
95
if (args.Length() != 1 || !args[0]->IsString()) {
96
return v8::ThrowException(v8::Exception::SyntaxError(
97
v8::String::New("Text input is required.")));
100
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
101
if (!break_iterator) {
102
return ThrowUnexpectedObjectError();
105
break_iterator->setText(*ResetAdoptedText(args.Holder(), args[0]));
107
return v8::Undefined();
110
v8::Handle<v8::Value> BreakIterator::BreakIteratorFirst(
111
const v8::Arguments& args) {
112
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
113
if (!break_iterator) {
114
return ThrowUnexpectedObjectError();
117
return v8::Int32::New(break_iterator->first());
120
v8::Handle<v8::Value> BreakIterator::BreakIteratorNext(
121
const v8::Arguments& args) {
122
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
123
if (!break_iterator) {
124
return ThrowUnexpectedObjectError();
127
return v8::Int32::New(break_iterator->next());
130
v8::Handle<v8::Value> BreakIterator::BreakIteratorCurrent(
131
const v8::Arguments& args) {
132
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
133
if (!break_iterator) {
134
return ThrowUnexpectedObjectError();
137
return v8::Int32::New(break_iterator->current());
140
v8::Handle<v8::Value> BreakIterator::BreakIteratorBreakType(
141
const v8::Arguments& args) {
142
icu::BreakIterator* break_iterator = UnpackBreakIterator(args.Holder());
143
if (!break_iterator) {
144
return ThrowUnexpectedObjectError();
147
// TODO(cira): Remove cast once ICU fixes base BreakIterator class.
148
icu::RuleBasedBreakIterator* rule_based_iterator =
149
static_cast<icu::RuleBasedBreakIterator*>(break_iterator);
150
int32_t status = rule_based_iterator->getRuleStatus();
151
// Keep return values in sync with JavaScript BreakType enum.
152
if (status >= UBRK_WORD_NONE && status < UBRK_WORD_NONE_LIMIT) {
153
return v8::Int32::New(UBRK_WORD_NONE);
154
} else if (status >= UBRK_WORD_NUMBER && status < UBRK_WORD_NUMBER_LIMIT) {
155
return v8::Int32::New(UBRK_WORD_NUMBER);
156
} else if (status >= UBRK_WORD_LETTER && status < UBRK_WORD_LETTER_LIMIT) {
157
return v8::Int32::New(UBRK_WORD_LETTER);
158
} else if (status >= UBRK_WORD_KANA && status < UBRK_WORD_KANA_LIMIT) {
159
return v8::Int32::New(UBRK_WORD_KANA);
160
} else if (status >= UBRK_WORD_IDEO && status < UBRK_WORD_IDEO_LIMIT) {
161
return v8::Int32::New(UBRK_WORD_IDEO);
163
return v8::Int32::New(-1);
167
v8::Handle<v8::Value> BreakIterator::JSBreakIterator(
168
const v8::Arguments& args) {
169
v8::HandleScope handle_scope;
171
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
172
return v8::ThrowException(v8::Exception::SyntaxError(
173
v8::String::New("Locale and iterator type are required.")));
176
v8::String::Utf8Value locale(args[0]);
177
icu::Locale icu_locale(*locale);
179
UErrorCode status = U_ZERO_ERROR;
180
icu::BreakIterator* break_iterator = NULL;
181
v8::String::Utf8Value type(args[1]);
182
if (!strcmp(*type, "character")) {
184
icu::BreakIterator::createCharacterInstance(icu_locale, status);
185
} else if (!strcmp(*type, "word")) {
187
icu::BreakIterator::createWordInstance(icu_locale, status);
188
} else if (!strcmp(*type, "sentence")) {
190
icu::BreakIterator::createSentenceInstance(icu_locale, status);
191
} else if (!strcmp(*type, "line")) {
193
icu::BreakIterator::createLineInstance(icu_locale, status);
195
return v8::ThrowException(v8::Exception::SyntaxError(
196
v8::String::New("Invalid iterator type.")));
199
if (U_FAILURE(status)) {
200
delete break_iterator;
201
return v8::ThrowException(v8::Exception::Error(
202
v8::String::New("Failed to create break iterator.")));
205
if (break_iterator_template_.IsEmpty()) {
206
v8::Local<v8::FunctionTemplate> raw_template(v8::FunctionTemplate::New());
208
raw_template->SetClassName(v8::String::New("v8Locale.v8BreakIterator"));
210
// Define internal field count on instance template.
211
v8::Local<v8::ObjectTemplate> object_template =
212
raw_template->InstanceTemplate();
214
// Set aside internal fields for icu break iterator and adopted text.
215
object_template->SetInternalFieldCount(2);
217
// Define all of the prototype methods on prototype template.
218
v8::Local<v8::ObjectTemplate> proto = raw_template->PrototypeTemplate();
219
proto->Set(v8::String::New("adoptText"),
220
v8::FunctionTemplate::New(BreakIteratorAdoptText));
221
proto->Set(v8::String::New("first"),
222
v8::FunctionTemplate::New(BreakIteratorFirst));
223
proto->Set(v8::String::New("next"),
224
v8::FunctionTemplate::New(BreakIteratorNext));
225
proto->Set(v8::String::New("current"),
226
v8::FunctionTemplate::New(BreakIteratorCurrent));
227
proto->Set(v8::String::New("breakType"),
228
v8::FunctionTemplate::New(BreakIteratorBreakType));
230
break_iterator_template_ =
231
v8::Persistent<v8::FunctionTemplate>::New(raw_template);
234
// Create an empty object wrapper.
235
v8::Local<v8::Object> local_object =
236
break_iterator_template_->GetFunction()->NewInstance();
237
v8::Persistent<v8::Object> wrapper =
238
v8::Persistent<v8::Object>::New(local_object);
240
// Set break iterator as internal field of the resulting JS object.
241
wrapper->SetPointerInInternalField(0, break_iterator);
242
// Make sure that the pointer to adopted text is NULL.
243
wrapper->SetPointerInInternalField(1, NULL);
245
// Make object handle weak so we can delete iterator once GC kicks in.
246
wrapper.MakeWeak(NULL, DeleteBreakIterator);
251
} // namespace v8_i18n