int findNextWordFromIndex(StringView text, int position, bool forward) { TextBreakIterator* it = wordBreakIterator(text); if (forward) { position = textBreakFollowing(it, position); while (position != TextBreakDone) { // We stop searching when the character preceeding the break is alphanumeric. if (static_cast<unsigned>(position) < text.length() && u_isalnum(text[position - 1])) return position; position = textBreakFollowing(it, position); } return text.length(); } else { position = textBreakPreceding(it, position); while (position != TextBreakDone) { // We stop searching when the character following the break is alphanumeric. if (position && u_isalnum(text[position])) return position; position = textBreakPreceding(it, position); } return 0; } }
int findNextWordFromIndex(const UChar* chars, int len, int position, bool forward) { TextBreakIterator* it = wordBreakIterator(chars, len); if (forward) { position = textBreakFollowing(it, position); while (position != TextBreakDone) { // We stop searching when the character preceeding the break // is alphanumeric. if (position < len && isAlphanumeric(chars[position - 1])) return position; position = textBreakFollowing(it, position); } return len; } else { position = textBreakPreceding(it, position); while (position != TextBreakDone) { // We stop searching when the character following the break // is alphanumeric. if (position > 0 && isAlphanumeric(chars[position])) return position; position = textBreakPreceding(it, position); } return 0; } }
int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, bool treatNoBreakSpaceAsBreak) { const UChar* str = lazyBreakIterator.string(); int len = lazyBreakIterator.length(); int nextBreak = -1; UChar lastCh = pos > 0 ? str[pos - 1] : 0; for (int i = pos; i < len; i++) { UChar ch = str[i]; if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh, ch)) return i; if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { if (nextBreak < i && i) { TextBreakIterator* breakIterator = lazyBreakIterator.get(); if (breakIterator) nextBreak = textBreakFollowing(breakIterator, i - 1); } // These characters are not kinsoku characters according to Unicode 6.0, // However, they are in JLreq (http://www.w3.org/TR/jlreq/). We need // special treatment here. if (i == nextBreak && !isBreakableSpace(lastCh, treatNoBreakSpaceAsBreak) && !Font::isUnbreakableCharactersPair(lastCh, ch)) return i; } lastCh = ch; } return len; }
void findEndWordBoundary(StringView text, int position, int* end) { TextBreakIterator* it = wordBreakIterator(text); *end = textBreakFollowing(it, position); if (*end < 0) *end = textBreakLast(it); }
int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, bool treatNoBreakSpaceAsBreak) { const UChar* str = lazyBreakIterator.string(); int len = lazyBreakIterator.length(); int nextBreak = -1; UChar lastLastCh = pos > 1 ? str[pos - 2] : 0; UChar lastCh = pos > 0 ? str[pos - 1] : 0; for (int i = pos; i < len; i++) { UChar ch = str[i]; if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastLastCh, lastCh, ch)) return i; if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { if (nextBreak < i && i) { TextBreakIterator* breakIterator = lazyBreakIterator.get(); if (breakIterator) nextBreak = textBreakFollowing(breakIterator, i - 1); } if (i == nextBreak && !isBreakableSpace(lastCh, treatNoBreakSpaceAsBreak)) return i; } lastLastCh = lastCh; lastCh = ch; } return len; }
void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end) { TextBreakIterator* it = wordBreakIterator(chars, len); *end = textBreakFollowing(it, position); if (*end < 0) *end = textBreakLast(it); *start = textBreakPrevious(it); }
void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end) { TextBreakIterator* it = wordBreakIterator(chars, len); *end = textBreakFollowing(it, position); if (*end < 0) *end = WebKitApollo::g_HostFunctions->textBreakLast(reinterpret_cast<void*>(it)); *start = WebKitApollo::g_HostFunctions->textBreakPrev(reinterpret_cast<void*>(it)); }
int nextBreakablePosition(const UChar* str, int pos, int len, bool treatNoBreakSpaceAsBreak) { #if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) TextBreakIterator* breakIterator = 0; #endif int nextBreak = -1; UChar lastCh = pos > 0 ? str[pos - 1] : 0; for (int i = pos; i < len; i++) { UChar ch = str[i]; if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastCh)) return i; if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { if (nextBreak < i && i) { #if !PLATFORM(MAC) || !defined(BUILDING_ON_TIGER) if (!breakIterator) breakIterator = lineBreakIterator(str, len); if (breakIterator) nextBreak = textBreakFollowing(breakIterator, i - 1); #else static TextBreakLocatorRef breakLocator = lineBreakLocator(); if (breakLocator) { UniCharArrayOffset nextUCBreak; if (UCFindTextBreak(breakLocator, kUCTextBreakLineMask, 0, str, len, i, &nextUCBreak) == 0) nextBreak = nextUCBreak; } #endif } if (i == nextBreak && !isBreakableSpace(lastCh, treatNoBreakSpaceAsBreak)) return i; } lastCh = ch; } return len; }
static inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, const CharacterType* str, unsigned length, int pos) { int len = static_cast<int>(length); int nextBreak = -1; CharacterType lastLastCh = pos > 1 ? str[pos - 2] : static_cast<CharacterType>(lazyBreakIterator.secondToLastCharacter()); CharacterType lastCh = pos > 0 ? str[pos - 1] : static_cast<CharacterType>(lazyBreakIterator.lastCharacter()); unsigned priorContextLength = lazyBreakIterator.priorContextLength(); for (int i = pos; i < len; i++) { CharacterType ch = str[i]; if (isBreakableSpace<treatNoBreakSpaceAsBreak>(ch) || shouldBreakAfter(lastLastCh, lastCh, ch)) return i; if (needsLineBreakIterator<treatNoBreakSpaceAsBreak, wordBreakSwitch>(ch) || needsLineBreakIterator<treatNoBreakSpaceAsBreak, wordBreakSwitch>(lastCh)) { if (nextBreak < i) { // Don't break if positioned at start of primary context and there is no prior context. if (i || priorContextLength) { TextBreakIterator* breakIterator = lazyBreakIterator.get(priorContextLength); if (breakIterator) { nextBreak = textBreakFollowing(breakIterator, i - 1 + priorContextLength); if (nextBreak >= 0) { nextBreak -= priorContextLength; } } } } if (i == nextBreak && !isBreakableSpace<treatNoBreakSpaceAsBreak>(lastCh)) return i; } lastLastCh = lastCh; lastCh = ch; } return len; }
static inline int boundedTextBreakFollowing(TextBreakIterator* it, int offset, int length) { int result = textBreakFollowing(it, offset); return result == TextBreakDone ? length : result; }
int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs) { // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or // approximate it by dividing the width of the ligature by the number of characters it encompasses. // However, Core Text does not expose a low-level API for directly finding // out how many characters a ligature encompasses (the "attachment count"). if (h >= m_totalWidth) return m_run.ltr() ? m_end : 0; if (h < 0) return m_run.ltr() ? 0 : m_end; CGFloat x = h; size_t runCount = m_coreTextRuns.size(); size_t offsetIntoAdjustedGlyphs = 0; for (size_t r = 0; r < runCount; ++r) { const CoreTextRun& coreTextRun = m_coreTextRuns[r]; for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) { CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width; if (x <= adjustedAdvance) { CFIndex hitIndex = coreTextRun.indexAt(j); int stringLength = coreTextRun.stringLength(); TextBreakIterator* characterIterator = characterBreakIterator(coreTextRun.characters(), stringLength); int clusterStart; if (isTextBreak(characterIterator, hitIndex)) clusterStart = hitIndex; else { clusterStart = textBreakPreceding(characterIterator, hitIndex); if (clusterStart == TextBreakDone) clusterStart = 0; } if (!includePartialGlyphs) return coreTextRun.stringLocation() + clusterStart; int clusterEnd = textBreakFollowing(characterIterator, hitIndex); if (clusterEnd == TextBreakDone) clusterEnd = stringLength; CGFloat clusterWidth = adjustedAdvance; // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns // derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no // reordering and on font fallback should occur within a CTLine. if (clusterEnd - clusterStart > 1) { int firstGlyphBeforeCluster = j - 1; while (firstGlyphBeforeCluster && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) { CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width; clusterWidth += width; x += width; firstGlyphBeforeCluster--; } unsigned firstGlyphAfterCluster = j + 1; while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) { clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width; firstGlyphAfterCluster++; } } if (x <= clusterWidth / 2) return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd); else return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart); } x -= adjustedAdvance; } offsetIntoAdjustedGlyphs += coreTextRun.glyphCount(); } ASSERT_NOT_REACHED(); return 0; }