summaryrefslogtreecommitdiffstats
path: root/gfx/graphite2/geckoextra
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/graphite2/geckoextra')
-rw-r--r--gfx/graphite2/geckoextra/include/GraphiteExtra.h42
-rw-r--r--gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h70
-rw-r--r--gfx/graphite2/geckoextra/src/GraphiteExtra.cpp167
3 files changed, 279 insertions, 0 deletions
diff --git a/gfx/graphite2/geckoextra/include/GraphiteExtra.h b/gfx/graphite2/geckoextra/include/GraphiteExtra.h
new file mode 100644
index 0000000000..9352e70991
--- /dev/null
+++ b/gfx/graphite2/geckoextra/include/GraphiteExtra.h
@@ -0,0 +1,42 @@
+// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vim: set ts=2 et sw=2 tw=80:
+// This Source Code is subject to the terms of the Mozilla Public License
+// version 2.0 (the "License"). You can obtain a copy of the License at
+// http://mozilla.org/MPL/2.0/.
+
+#ifndef GraphiteExtra_h__
+#define GraphiteExtra_h__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "graphite2/Segment.h"
+
+typedef struct {
+ uint32_t baseChar; // in UTF16 code units, not Unicode character indices
+ uint32_t baseGlyph;
+ uint32_t nChars; // UTF16 code units
+ uint32_t nGlyphs;
+} gr_glyph_to_char_cluster;
+
+typedef struct {
+ gr_glyph_to_char_cluster* clusters;
+ uint16_t* gids;
+ float* xLocs;
+ float* yLocs;
+ uint32_t cIndex;
+} gr_glyph_to_char_association;
+
+gr_glyph_to_char_association* gr_get_glyph_to_char_association(
+ gr_segment* aSegment, uint32_t aLength, const char16_t* aText);
+
+void gr_free_char_association(gr_glyph_to_char_association* aData);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h b/gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h
new file mode 100644
index 0000000000..64fb198936
--- /dev/null
+++ b/gfx/graphite2/geckoextra/include/GraphiteStructsForRLBox.h
@@ -0,0 +1,70 @@
+// -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vim: set ts=2 et sw=2 tw=80:
+// This Source Code is subject to the terms of the Mozilla Public License
+// version 2.0 (the "License"). You can obtain a copy of the License at
+// http://mozilla.org/MPL/2.0/.
+
+#ifndef GraphiteStructsForRLBox_h__
+#define GraphiteStructsForRLBox_h__
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#elif defined(__GNUC__) || defined(__GNUG__)
+// Can't turn off the variadic macro warning emitted from -pedantic
+# pragma GCC system_header
+#elif defined(_MSC_VER)
+// Doesn't seem to emit the warning
+#else
+// Don't know the compiler... just let it go through
+#endif
+
+// Note that the two size fields below are actually size_t in the headers
+// However RLBox currently does not handle these correctly. See Bug 1722127.
+// Use a workaround of unsiged int instead of size_t.
+#define sandbox_fields_reflection_graphite_class_gr_font_ops(f, g, ...) \
+ f(unsigned int, size, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(float (*)(const void*, unsigned short), glyph_advance_x, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(float (*)(const void*, unsigned short), glyph_advance_y, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_face_ops(f, g, ...) \
+ f(unsigned int, size, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(const void* (*)(const void*, unsigned int, unsigned int*), get_table, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(void (*)(const void*, const void*), release_table, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_glyph_to_char_cluster(f, g, ...) \
+ f(unsigned int, baseChar, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned int, baseGlyph, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned int, nChars, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned int, nGlyphs, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_glyph_to_char_association(f, g, ...) \
+ f(gr_glyph_to_char_cluster*, clusters, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned short*, gids, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(float*, xLocs, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(float*, yLocs, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned int, cIndex, FIELD_NORMAL, ##__VA_ARGS__) g()
+
+#define sandbox_fields_reflection_graphite_class_gr_faceinfo(f, g, ...) \
+ f(short, extra_ascent, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(short, extra_descent, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(short, upem, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(gr_faceinfo::gr_space_contextuals, space_contextuals, FIELD_NORMAL, ##__VA_ARGS__) g() \
+ f(unsigned int, has_bidi_pass, FIELD_NORMAL, ##__VA_ARGS__) g()
+ // Remaining bitfields skipped, as bitfields are not fully supported
+
+#define sandbox_fields_reflection_graphite_allClasses(f, ...) \
+ f(gr_font_ops, graphite, ##__VA_ARGS__) \
+ f(gr_face_ops, graphite, ##__VA_ARGS__) \
+ f(gr_glyph_to_char_cluster, graphite, ##__VA_ARGS__) \
+ f(gr_glyph_to_char_association, graphite, ##__VA_ARGS__) \
+ f(gr_faceinfo, graphite, ##__VA_ARGS__)
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#elif defined(__GNUC__) || defined(__GNUG__)
+#elif defined(_MSC_VER)
+#else
+#endif
+
+#endif \ No newline at end of file
diff --git a/gfx/graphite2/geckoextra/src/GraphiteExtra.cpp b/gfx/graphite2/geckoextra/src/GraphiteExtra.cpp
new file mode 100644
index 0000000000..b5c8802b15
--- /dev/null
+++ b/gfx/graphite2/geckoextra/src/GraphiteExtra.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "graphite2/Font.h"
+#include "graphite2/Segment.h"
+#include "graphite2/GraphiteExtra.h"
+
+#include <stdlib.h>
+#include <memory>
+#include <limits>
+
+#define CHECK(cond, str) \
+ do { \
+ if (!(cond)) { \
+ return false; \
+ } \
+ } while (false)
+
+// High surrogates are in the range 0xD800 -- OxDBFF
+#define NS_IS_HIGH_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xD800)
+// Low surrogates are in the range 0xDC00 -- 0xDFFF
+#define NS_IS_LOW_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xDC00)
+
+#define IS_POWER_OF_2(n) (n & (n - 1)) == 0
+
+typedef gr_glyph_to_char_cluster Cluster;
+
+// returns whether successful
+static bool LoopThrough(gr_segment* aSegment, const uint32_t aLength,
+ const uint32_t aGlyphCount, const char16_t* aText,
+ uint32_t& aCIndex, Cluster* aClusters, uint16_t* aGids,
+ float* aXLocs, float* aYLocs) {
+ // walk through the glyph slots and check which original character
+ // each is associated with
+ uint32_t gIndex = 0; // glyph slot index
+ for (const gr_slot* slot = gr_seg_first_slot(aSegment); slot != nullptr;
+ slot = gr_slot_next_in_segment(slot), gIndex++) {
+ CHECK(gIndex < aGlyphCount, "iterating past glyphcount");
+ uint32_t before =
+ gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_before(slot)));
+ uint32_t after = gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_after(slot)));
+ aGids[gIndex] = gr_slot_gid(slot);
+ aXLocs[gIndex] = gr_slot_origin_X(slot);
+ aYLocs[gIndex] = gr_slot_origin_Y(slot);
+
+ // if this glyph has a "before" character index that precedes the
+ // current cluster's char index, we need to merge preceding
+ // aClusters until it gets included
+ while (before < aClusters[aCIndex].baseChar && aCIndex > 0) {
+ aClusters[aCIndex - 1].nChars += aClusters[aCIndex].nChars;
+ aClusters[aCIndex - 1].nGlyphs += aClusters[aCIndex].nGlyphs;
+ --aCIndex;
+ }
+
+ // if there's a gap between the current cluster's base character and
+ // this glyph's, extend the cluster to include the intervening chars
+ if (gr_slot_can_insert_before(slot) && aClusters[aCIndex].nChars &&
+ before >= aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars) {
+ CHECK(aCIndex < aLength - 1, "aCIndex at end of word");
+ Cluster& c = aClusters[aCIndex + 1];
+ c.baseChar = aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars;
+ c.nChars = before - c.baseChar;
+ c.baseGlyph = gIndex;
+ c.nGlyphs = 0;
+ ++aCIndex;
+ }
+
+ // increment cluster's glyph count to include current slot
+ CHECK(aCIndex < aLength, "aCIndex beyond word length");
+ ++aClusters[aCIndex].nGlyphs;
+
+ // bump |after| index if it falls in the middle of a surrogate pair
+ if (NS_IS_HIGH_SURROGATE(aText[after]) && after < aLength - 1 &&
+ NS_IS_LOW_SURROGATE(aText[after + 1])) {
+ after++;
+ }
+
+ // extend cluster if necessary to reach the glyph's "after" index
+ if (aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars < after + 1) {
+ aClusters[aCIndex].nChars = after + 1 - aClusters[aCIndex].baseChar;
+ }
+ }
+
+ // Succeeded
+ return true;
+}
+
+static gr_glyph_to_char_association* calloc_glyph_to_char_association(
+ uint32_t aGlyphCount, uint32_t aLength) {
+ using Type1 = gr_glyph_to_char_association;
+ using Type2 = gr_glyph_to_char_cluster;
+ using Type3 = float;
+ using Type4 = float;
+ using Type5 = uint16_t;
+
+ // We are allocating memory in a pool. To avoid dealing with thorny alignment
+ // issues, we allocate from most to least aligned
+ static_assert(
+ alignof(Type1) >= alignof(Type2) && alignof(Type2) >= alignof(Type3) &&
+ alignof(Type3) >= alignof(Type4) && alignof(Type4) >= alignof(Type5),
+ "Unexpected alignments of types");
+
+ const uint64_t size1 = sizeof(Type1) * static_cast<uint64_t>(1);
+ const uint64_t size2 = sizeof(Type2) * static_cast<uint64_t>(aLength);
+ const uint64_t size3 = sizeof(Type3) * static_cast<uint64_t>(aGlyphCount);
+ const uint64_t size4 = sizeof(Type4) * static_cast<uint64_t>(aGlyphCount);
+ const uint64_t size5 = sizeof(Type5) * static_cast<uint64_t>(aGlyphCount);
+
+ uint64_t totalSize = size1 + size2 + size3 + size4 + size5;
+
+ if (totalSize > std::numeric_limits<uint32_t>::max()) {
+ // allocation request got too large
+ return nullptr;
+ }
+
+ char* const memoryPool = static_cast<char*>(calloc(1, totalSize));
+ if (!memoryPool) {
+ return nullptr;
+ }
+
+ char* currentPoolFront = memoryPool;
+
+ auto data = reinterpret_cast<Type1*>(currentPoolFront);
+ currentPoolFront += size1;
+ data->clusters = reinterpret_cast<Type2*>(currentPoolFront);
+ currentPoolFront += size2;
+ data->xLocs = reinterpret_cast<Type3*>(currentPoolFront);
+ currentPoolFront += size3;
+ data->yLocs = reinterpret_cast<Type4*>(currentPoolFront);
+ currentPoolFront += size4;
+ data->gids = reinterpret_cast<Type5*>(currentPoolFront);
+
+ return data;
+}
+
+// returns nullptr on failure and the glyph to char association on success
+gr_glyph_to_char_association* gr_get_glyph_to_char_association(
+ gr_segment* aSegment, uint32_t aLength, const char16_t* aText) {
+ uint32_t glyphCount = gr_seg_n_slots(aSegment);
+
+ gr_glyph_to_char_association* data =
+ calloc_glyph_to_char_association(glyphCount, aLength);
+ if (!data) {
+ return nullptr;
+ }
+
+ bool succeeded =
+ LoopThrough(aSegment, aLength, glyphCount, aText, data->cIndex,
+ data->clusters, data->gids, data->xLocs, data->yLocs);
+ if (!succeeded) {
+ gr_free_char_association(data);
+ return nullptr;
+ }
+ return data;
+}
+
+void gr_free_char_association(gr_glyph_to_char_association* aData) {
+ free(aData);
+}
+
+#undef CHECK
+#undef NS_IS_HIGH_SURROGATE
+#undef NS_IS_LOW_SURROGATE
+#undef IS_POWER_OF_2