summaryrefslogtreecommitdiff
path: root/js/src/builtin/intl/CommonFunctions.h
blob: c6856c9b6d59f3ef82bcbd1b19306507f5958afa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef builtin_intl_CommonFunctions_h
#define builtin_intl_CommonFunctions_h

#include "mozilla/Assertions.h"
#include "mozilla/TypeTraits.h"

#include <stddef.h>
#include <stdint.h>
#include <string.h>

#include "builtin/intl/ICUHeader.h"
#include "js/RootingAPI.h"
#include "js/Vector.h"
#include "vm/String.h"

namespace JS { class Value; }

class JSObject;

namespace js {

namespace intl {

/**
 * Initialize a new Intl.* object using the named self-hosted function.
 */
extern bool
InitializeObject(JSContext* cx, HandleObject obj, Handle<PropertyName*> initializer,
                 HandleValue locales, HandleValue options);

/**
 * Initialize an existing object as an Intl.* object using the named
 * self-hosted function.  This is only for a few old Intl.* constructors, for
 * legacy reasons -- new ones should use the function above instead.
 */

enum class DateTimeFormatOptions
{
    Standard,
    EnableMozExtensions,
};

extern bool
LegacyIntlInitialize(JSContext* cx, HandleObject obj, Handle<PropertyName*> initializer,
                     HandleValue thisValue, HandleValue locales, HandleValue options,
                     DateTimeFormatOptions dtfOptions, MutableHandleValue result);
/**
 * Returns the object holding the internal properties for obj.
 */
extern JSObject*
GetInternalsObject(JSContext* cx, JS::Handle<JSObject*> obj);

/** Report an Intl internal error not directly tied to a spec step. */
extern void
ReportInternalError(JSContext* cx);

static inline bool
StringsAreEqual(const char* s1, const char* s2)
{
    return !strcmp(s1, s2);
}

static inline bool
StringsAreEqual(JSAutoByteString& s1, const char* s2)
{
    return !strcmp(s1.ptr(), s2);
}

/**
 * The last-ditch locale is used if none of the available locales satisfies a
 * request. "en-GB" is used based on the assumptions that English is the most
 * common second language, that both en-GB and en-US are normally available in
 * an implementation, and that en-GB is more representative of the English used
 * in other locales.
 */
static inline const char* LastDitchLocale() { return "en-GB"; }

/**
 * Certain old, commonly-used language tags that lack a script, are expected to
 * nonetheless imply one. This object maps these old-style tags to modern
 * equivalents.
 */
struct OldStyleLanguageTagMapping {
  const char* const oldStyle;
  const char* const modernStyle;

  // Provide a constructor to catch missing initializers in the mappings array.
  constexpr OldStyleLanguageTagMapping(const char* oldStyle,
                                       const char* modernStyle)
      : oldStyle(oldStyle), modernStyle(modernStyle) {}
};

extern const OldStyleLanguageTagMapping oldStyleLanguageTagMappings[5];

static inline const char*
IcuLocale(const char* locale)
{
    if (StringsAreEqual(locale, "und"))
        return ""; // ICU root locale

    return locale;
}

// Starting with ICU 59, UChar defaults to char16_t.
static_assert(mozilla::IsSame<UChar, char16_t>::value,
              "SpiderMonkey doesn't support redefining UChar to a different type");

// The inline capacity we use for a Vector<char16_t>.  Use this to ensure that
// our uses of ICU string functions, below and elsewhere, will try to fill the
// buffer's entire inline capacity before growing it and heap-allocating.
static const size_t INITIAL_CHAR_BUFFER_SIZE = 32;

template <typename ICUStringFunction, typename CharT, size_t InlineCapacity>
static int32_t
CallICU(JSContext* cx, Vector<CharT, InlineCapacity>& chars, const ICUStringFunction& strFn)
{
    MOZ_ASSERT(chars.length() == 0);
    MOZ_ALWAYS_TRUE(chars.resize(InlineCapacity));

    UErrorCode status = U_ZERO_ERROR;
    int32_t size = strFn(chars.begin(), InlineCapacity, &status);
    if (status == U_BUFFER_OVERFLOW_ERROR) {
        MOZ_ASSERT(size >= 0);
        if (!chars.resize(size_t(size)))
            return -1;
        status = U_ZERO_ERROR;
        strFn(chars.begin(), size, &status);
    }
    if (U_FAILURE(status)) {
        ReportInternalError(cx);
        return -1;
    }

    MOZ_ASSERT(size >= 0);
    if (!chars.resize(size_t(size)))
        return -1;
    return size;
}

template <typename ICUStringFunction>
static JSString*
CallICU(JSContext* cx, const ICUStringFunction& strFn)
{
    Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);

    int32_t size = CallICU(cx, chars, strFn);
    if (size < 0)
        return nullptr;

    return NewStringCopyN<CanGC>(cx, chars.begin(), size_t(size));
}

} // namespace intl

} // namespace js

#endif /* builtin_intl_CommonFunctions_h */