GraphiteExtra.cpp (6152B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "graphite2/Font.h" 8 #include "graphite2/Segment.h" 9 #include "graphite2/GraphiteExtra.h" 10 11 #include <stdlib.h> 12 #include <memory> 13 #include <limits> 14 15 #define CHECK(cond, str) \ 16 do { \ 17 if (!(cond)) { \ 18 return false; \ 19 } \ 20 } while (false) 21 22 // High surrogates are in the range 0xD800 -- OxDBFF 23 #define NS_IS_HIGH_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xD800) 24 // Low surrogates are in the range 0xDC00 -- 0xDFFF 25 #define NS_IS_LOW_SURROGATE(u) ((uint32_t(u) & 0xFFFFFC00) == 0xDC00) 26 27 #define IS_POWER_OF_2(n) (n & (n - 1)) == 0 28 29 typedef gr_glyph_to_char_cluster Cluster; 30 31 // returns whether successful 32 static bool LoopThrough(gr_segment* aSegment, const uint32_t aLength, 33 const uint32_t aGlyphCount, const char16_t* aText, 34 uint32_t& aCIndex, Cluster* aClusters, uint16_t* aGids, 35 float* aXLocs, float* aYLocs) { 36 // walk through the glyph slots and check which original character 37 // each is associated with 38 uint32_t gIndex = 0; // glyph slot index 39 for (const gr_slot* slot = gr_seg_first_slot(aSegment); slot != nullptr; 40 slot = gr_slot_next_in_segment(slot), gIndex++) { 41 CHECK(gIndex < aGlyphCount, "iterating past glyphcount"); 42 uint32_t before = 43 gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_before(slot))); 44 uint32_t after = gr_cinfo_base(gr_seg_cinfo(aSegment, gr_slot_after(slot))); 45 aGids[gIndex] = gr_slot_gid(slot); 46 aXLocs[gIndex] = gr_slot_origin_X(slot); 47 aYLocs[gIndex] = gr_slot_origin_Y(slot); 48 49 // if this glyph has a "before" character index that precedes the 50 // current cluster's char index, we need to merge preceding 51 // aClusters until it gets included 52 while (before < aClusters[aCIndex].baseChar && aCIndex > 0) { 53 aClusters[aCIndex - 1].nChars += aClusters[aCIndex].nChars; 54 aClusters[aCIndex - 1].nGlyphs += aClusters[aCIndex].nGlyphs; 55 --aCIndex; 56 } 57 58 // if there's a gap between the current cluster's base character and 59 // this glyph's, extend the cluster to include the intervening chars 60 if (gr_slot_can_insert_before(slot) && aClusters[aCIndex].nChars && 61 before >= aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars) { 62 CHECK(aCIndex < aLength - 1, "aCIndex at end of word"); 63 Cluster& c = aClusters[aCIndex + 1]; 64 c.baseChar = aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars; 65 c.nChars = before - c.baseChar; 66 c.baseGlyph = gIndex; 67 c.nGlyphs = 0; 68 ++aCIndex; 69 } 70 71 // increment cluster's glyph count to include current slot 72 CHECK(aCIndex < aLength, "aCIndex beyond word length"); 73 ++aClusters[aCIndex].nGlyphs; 74 75 // bump |after| index if it falls in the middle of a surrogate pair 76 if (NS_IS_HIGH_SURROGATE(aText[after]) && after < aLength - 1 && 77 NS_IS_LOW_SURROGATE(aText[after + 1])) { 78 after++; 79 } 80 81 // extend cluster if necessary to reach the glyph's "after" index 82 if (aClusters[aCIndex].baseChar + aClusters[aCIndex].nChars < after + 1) { 83 aClusters[aCIndex].nChars = after + 1 - aClusters[aCIndex].baseChar; 84 } 85 } 86 87 // Succeeded 88 return true; 89 } 90 91 static gr_glyph_to_char_association* calloc_glyph_to_char_association( 92 uint32_t aGlyphCount, uint32_t aLength) { 93 using Type1 = gr_glyph_to_char_association; 94 using Type2 = gr_glyph_to_char_cluster; 95 using Type3 = float; 96 using Type4 = float; 97 using Type5 = uint16_t; 98 99 // We are allocating memory in a pool. To avoid dealing with thorny alignment 100 // issues, we allocate from most to least aligned 101 static_assert( 102 alignof(Type1) >= alignof(Type2) && alignof(Type2) >= alignof(Type3) && 103 alignof(Type3) >= alignof(Type4) && alignof(Type4) >= alignof(Type5), 104 "Unexpected alignments of types"); 105 106 const uint64_t size1 = sizeof(Type1) * static_cast<uint64_t>(1); 107 const uint64_t size2 = sizeof(Type2) * static_cast<uint64_t>(aLength); 108 const uint64_t size3 = sizeof(Type3) * static_cast<uint64_t>(aGlyphCount); 109 const uint64_t size4 = sizeof(Type4) * static_cast<uint64_t>(aGlyphCount); 110 const uint64_t size5 = sizeof(Type5) * static_cast<uint64_t>(aGlyphCount); 111 112 uint64_t totalSize = size1 + size2 + size3 + size4 + size5; 113 114 if (totalSize > std::numeric_limits<uint32_t>::max()) { 115 // allocation request got too large 116 return nullptr; 117 } 118 119 char* const memoryPool = static_cast<char*>(calloc(1, totalSize)); 120 if (!memoryPool) { 121 return nullptr; 122 } 123 124 char* currentPoolFront = memoryPool; 125 126 auto data = reinterpret_cast<Type1*>(currentPoolFront); 127 currentPoolFront += size1; 128 data->clusters = reinterpret_cast<Type2*>(currentPoolFront); 129 currentPoolFront += size2; 130 data->xLocs = reinterpret_cast<Type3*>(currentPoolFront); 131 currentPoolFront += size3; 132 data->yLocs = reinterpret_cast<Type4*>(currentPoolFront); 133 currentPoolFront += size4; 134 data->gids = reinterpret_cast<Type5*>(currentPoolFront); 135 136 return data; 137 } 138 139 // returns nullptr on failure and the glyph to char association on success 140 gr_glyph_to_char_association* gr_get_glyph_to_char_association( 141 gr_segment* aSegment, uint32_t aLength, const char16_t* aText) { 142 uint32_t glyphCount = gr_seg_n_slots(aSegment); 143 144 gr_glyph_to_char_association* data = 145 calloc_glyph_to_char_association(glyphCount, aLength); 146 if (!data) { 147 return nullptr; 148 } 149 150 bool succeeded = 151 LoopThrough(aSegment, aLength, glyphCount, aText, data->cIndex, 152 data->clusters, data->gids, data->xLocs, data->yLocs); 153 if (!succeeded) { 154 gr_free_char_association(data); 155 return nullptr; 156 } 157 return data; 158 } 159 160 void gr_free_char_association(gr_glyph_to_char_association* aData) { 161 free(aData); 162 } 163 164 #undef CHECK 165 #undef NS_IS_HIGH_SURROGATE 166 #undef NS_IS_LOW_SURROGATE 167 #undef IS_POWER_OF_2