Split string into segments with uniform text properties
| 117 | |
| 118 | // Split string into segments with uniform text properties |
| 119 | std::vector<TextSegment> segmentString(const sf::String& input) |
| 120 | { |
| 121 | std::vector<TextSegment> segments; |
| 122 | |
| 123 | const SBCodepointSequence codepointSequence{SBStringEncodingUTF32, |
| 124 | static_cast<const void*>(input.getData()), |
| 125 | input.getSize()}; |
| 126 | auto* const scriptLocator = SBScriptLocatorCreate(); |
| 127 | const auto* const algorithm = SBAlgorithmCreate(&codepointSequence); |
| 128 | SBUInteger paragraphOffset = 0; |
| 129 | |
| 130 | while (paragraphOffset < input.getSize()) |
| 131 | { |
| 132 | SBUInteger paragraphLength{}; |
| 133 | SBUInteger separatorLength{}; |
| 134 | SBAlgorithmGetParagraphBoundary(algorithm, |
| 135 | paragraphOffset, |
| 136 | std::numeric_limits<SBUInteger>::max(), |
| 137 | ¶graphLength, |
| 138 | &separatorLength); |
| 139 | |
| 140 | // If the paragraph contains characters besides the separator, |
| 141 | // split the separator off into its own paragraph in the next iteration |
| 142 | // We do this to ensure line breaks are inserted into segments last |
| 143 | // after all character runs on the same line have already been inserted |
| 144 | // This allows us to draw our segments in left-to-right top-to-bottom order |
| 145 | if (separatorLength < paragraphLength) |
| 146 | paragraphLength -= separatorLength; |
| 147 | |
| 148 | const auto* const paragraph = SBAlgorithmCreateParagraph(algorithm, paragraphOffset, paragraphLength, SBLevelDefaultLTR); |
| 149 | const auto* const line = SBParagraphCreateLine(paragraph, paragraphOffset, paragraphLength); |
| 150 | const auto runCount = SBLineGetRunCount(line); |
| 151 | const auto* runArray = SBLineGetRunsPtr(line); |
| 152 | |
| 153 | for (SBUInteger i = 0; i < runCount; i++) |
| 154 | { |
| 155 | // Odd levels are RTL, even levels are LTR |
| 156 | const auto direction = (runArray[i].level % 2) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR; |
| 157 | |
| 158 | const SBCodepointSequence codepointSubsequence{SBStringEncodingUTF32, |
| 159 | static_cast<const void*>(input.getData() + runArray[i].offset), |
| 160 | runArray[i].length}; |
| 161 | |
| 162 | SBScriptLocatorLoadCodepoints(scriptLocator, &codepointSubsequence); |
| 163 | |
| 164 | while (SBScriptLocatorMoveNext(scriptLocator)) |
| 165 | { |
| 166 | const auto* agent = SBScriptLocatorGetAgent(scriptLocator); |
| 167 | const auto script = hb_script_from_iso15924_tag(SBScriptGetUnicodeTag(agent->script)); |
| 168 | |
| 169 | segments.emplace_back(TextSegment{runArray[i].offset + agent->offset, agent->length, script, direction}); |
| 170 | } |
| 171 | |
| 172 | SBScriptLocatorReset(scriptLocator); |
| 173 | } |
| 174 | |
| 175 | SBLineRelease(line); |
| 176 | SBParagraphRelease(paragraph); |
no test coverage detected