int ComplexTextController::offsetForPosition(int targetX) { unsigned basePosition = 0; int x = offsetX(); while (nextScriptRun()) { int nextX = offsetX(); if (std::min(x, nextX) <= targetX && targetX <= std::max(x, nextX)) { // The x value in question is within this script run. const int glyphIndex = glyphIndexForXPositionInScriptRun(targetX); // Now that we have a glyph index, we have to turn that into a // code-point index. Because of ligatures, several code-points may // have gone into a single glyph. We iterate over the clusters log // and find the first code-point which contributed to the glyph. // Some shapers (i.e. Khmer) will produce cluster logs which report // that /no/ code points contributed to certain glyphs. Because of // this, we take any code point which contributed to the glyph in // question, or any subsequent glyph. If we run off the end, then // we take the last code point. for (unsigned j = 0; j < numCodePoints(); ++j) { if (m_item.log_clusters[j] >= glyphIndex) return basePosition + j; } return basePosition + numCodePoints() - 1; } basePosition += numCodePoints(); } return basePosition; }
// Return the code point index for the given |x| offset into the text run. int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const { // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem. int targetX = static_cast<int>(xFloat); // (Mac code ignores includePartialGlyphs, and they don't know what it's // supposed to do, so we just ignore it as well.) ComplexTextController controller(run, 0, 0, this); controller.setWordSpacingAdjustment(wordSpacing()); controller.setLetterSpacingAdjustment(letterSpacing()); controller.setPadding(run.expansion()); if (run.rtl()) { // See FIXME in drawComplexText. controller.reset(controller.widthOfFullRun()); controller.setPadding(run.expansion()); } unsigned basePosition = 0; int x = controller.offsetX(); while (controller.nextScriptRun()) { int nextX = controller.offsetX(); if (std::min(x, nextX) <= targetX && targetX <= std::max(x, nextX)) { // The x value in question is within this script run. const int glyphIndex = glyphIndexForXPositionInScriptRun(controller, targetX); // Now that we have a glyph index, we have to turn that into a // code-point index. Because of ligatures, several code-points may // have gone into a single glyph. We iterate over the clusters log // and find the first code-point which contributed to the glyph. // Some shapers (i.e. Khmer) will produce cluster logs which report // that /no/ code points contributed to certain glyphs. Because of // this, we take any code point which contributed to the glyph in // question, or any subsequent glyph. If we run off the end, then // we take the last code point. const unsigned short* log = controller.logClusters(); for (unsigned j = 0; j < controller.numCodePoints(); ++j) { if (log[j] >= glyphIndex) return basePosition + j; } return basePosition + controller.numCodePoints() - 1; } basePosition += controller.numCodePoints(); } return basePosition; }
// Return the code point index for the given |x| offset into the text run. int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const { // (Mac code ignores includePartialGlyphs, and they don't know what it's // supposed to do, so we just ignore it as well.) TextRunWalker walker(run, 0, this); // If this is RTL text, the first glyph from the left is actually the last // code point. So we need to know how many code points there are total in // order to subtract. This is different from the length of the TextRun // because UTF-16 surrogate pairs are a single code point, but 32-bits long. // In LTR we leave this as 0 so that we get the correct value for // |basePosition|, below. unsigned totalCodePoints = 0; if (walker.rtl()) { ssize_t offset = 0; while (offset < run.length()) { utf16_to_code_point(run.characters(), run.length(), &offset); totalCodePoints++; } } unsigned basePosition = totalCodePoints; // For RTL: // code-point order: abcd efg hijkl // on screen: lkjih gfe dcba // ^ ^ // | | // basePosition--| | // totalCodePoints----| // Since basePosition is currently the total number of code-points, the // first thing we do is decrement it so that it's pointing to the start of // the current script-run. // // For LTR, basePosition is zero so it already points to the start of the // first script run. while (walker.nextScriptRun()) { if (walker.rtl()) basePosition -= walker.numCodePoints(); if (x < walker.width()) { // The x value in question is within this script run. We consider // each glyph in presentation order and stop when we find the one // covering this position. const int glyphIndex = glyphIndexForXPositionInScriptRun(walker, x); // Now that we have a glyph index, we have to turn that into a // code-point index. Because of ligatures, several code-points may // have gone into a single glyph. We iterate over the clusters log // and find the first code-point which contributed to the glyph. // Some shapers (i.e. Khmer) will produce cluster logs which report // that /no/ code points contributed to certain glyphs. Because of // this, we take any code point which contributed to the glyph in // question, or any subsequent glyph. If we run off the end, then // we take the last code point. const unsigned short* log = walker.logClusters(); for (unsigned j = 0; j < walker.numCodePoints(); ++j) { if (log[j] >= glyphIndex) return basePosition + j; } return basePosition + walker.numCodePoints() - 1; } x -= walker.width(); if (!walker.rtl()) basePosition += walker.numCodePoints(); } return basePosition; }