Fix hyperlink tags in Arabic
This commit is contained in:
@@ -299,6 +299,7 @@ void CGraphicTextInstance::Update()
|
|||||||
wchar_t ch;
|
wchar_t ch;
|
||||||
DWORD color;
|
DWORD color;
|
||||||
int linkIndex; // -1 = none, otherwise index into linkTargets
|
int linkIndex; // -1 = none, otherwise index into linkTargets
|
||||||
|
int logicalPos; // logical index in original wTextBuf (includes tags)
|
||||||
};
|
};
|
||||||
|
|
||||||
auto ReorderTaggedWithBidi = [&](std::vector<TVisChar>& vis, bool forceRTL)
|
auto ReorderTaggedWithBidi = [&](std::vector<TVisChar>& vis, bool forceRTL)
|
||||||
@@ -386,7 +387,7 @@ void CGraphicTextInstance::Update()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Regular visible character
|
// Regular visible character
|
||||||
logicalVis.push_back(TVisChar{ ch, curColor, activeLinkIndex });
|
logicalVis.push_back(TVisChar{ ch, curColor, activeLinkIndex, i });
|
||||||
}
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
@@ -430,21 +431,6 @@ void CGraphicTextInstance::Update()
|
|||||||
i += tagLen;
|
i += tagLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete position mappings
|
|
||||||
const int logicalVisSize = (int)logicalVis.size();
|
|
||||||
m_logicalToVisualPos[wTextLen] = logicalVisSize;
|
|
||||||
|
|
||||||
m_visualToLogicalPos.resize((size_t)logicalVisSize + 1);
|
|
||||||
const size_t logicalToVisualSize = m_logicalToVisualPos.size();
|
|
||||||
const int visualToLogicalSize = (int)m_visualToLogicalPos.size();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < logicalToVisualSize; ++i)
|
|
||||||
{
|
|
||||||
const int visualPos = m_logicalToVisualPos[i];
|
|
||||||
if (visualPos >= 0 && visualPos < visualToLogicalSize)
|
|
||||||
m_visualToLogicalPos[visualPos] = (int)i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
// PHASE 2: Apply BiDi to hyperlinks (if RTL text or RTL UI)
|
// PHASE 2: Apply BiDi to hyperlinks (if RTL text or RTL UI)
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
@@ -564,7 +550,7 @@ void CGraphicTextInstance::Update()
|
|||||||
|
|
||||||
// Write back - handle size changes by erasing/inserting
|
// Write back - handle size changes by erasing/inserting
|
||||||
const int originalSize = linkLength;
|
const int originalSize = linkLength;
|
||||||
const int newSize = linkVisualSize;
|
const int newSize = (int)linkVisual.size();
|
||||||
const int sizeDiff = newSize - originalSize;
|
const int sizeDiff = newSize - originalSize;
|
||||||
|
|
||||||
// Replace existing characters (cache min for performance)
|
// Replace existing characters (cache min for performance)
|
||||||
@@ -582,6 +568,7 @@ void CGraphicTextInstance::Update()
|
|||||||
{
|
{
|
||||||
// Grew - insert new characters
|
// Grew - insert new characters
|
||||||
TVisChar templateChar = logicalVis[linkStart];
|
TVisChar templateChar = logicalVis[linkStart];
|
||||||
|
templateChar.logicalPos = logicalVis[linkStart].logicalPos;
|
||||||
for (int j = originalSize; j < newSize; ++j)
|
for (int j = originalSize; j < newSize; ++j)
|
||||||
{
|
{
|
||||||
templateChar.ch = linkVisual[j];
|
templateChar.ch = linkVisual[j];
|
||||||
@@ -652,6 +639,45 @@ void CGraphicTextInstance::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====================================================================
|
||||||
|
// FINAL: Rebuild visual<->logical mapping AFTER all BiDi/tag reordering
|
||||||
|
// ====================================================================
|
||||||
|
|
||||||
|
m_visualToLogicalPos.clear();
|
||||||
|
m_logicalToVisualPos.clear();
|
||||||
|
|
||||||
|
// logical positions refer to indices in wTextBuf (tagged string)
|
||||||
|
m_logicalToVisualPos.resize((size_t)wTextLen + 1, -1);
|
||||||
|
m_visualToLogicalPos.resize((size_t)logicalVis.size() + 1, wTextLen);
|
||||||
|
|
||||||
|
// Fill visual->logical from stored glyph origin
|
||||||
|
for (size_t v = 0; v < logicalVis.size(); ++v)
|
||||||
|
{
|
||||||
|
int lp = logicalVis[v].logicalPos;
|
||||||
|
if (lp < 0) lp = 0;
|
||||||
|
if (lp > wTextLen) lp = wTextLen;
|
||||||
|
|
||||||
|
m_visualToLogicalPos[v] = lp;
|
||||||
|
|
||||||
|
// For logical->visual, keep the first visual position that maps to lp
|
||||||
|
if (m_logicalToVisualPos[(size_t)lp] < 0)
|
||||||
|
m_logicalToVisualPos[(size_t)lp] = (int)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End positions
|
||||||
|
m_visualToLogicalPos[logicalVis.size()] = wTextLen;
|
||||||
|
m_logicalToVisualPos[(size_t)wTextLen] = (int)logicalVis.size();
|
||||||
|
|
||||||
|
// Fill gaps in logical->visual so cursor movement doesn't break on tag-only regions
|
||||||
|
int last = 0;
|
||||||
|
for (int i = 0; i <= wTextLen; ++i)
|
||||||
|
{
|
||||||
|
if (m_logicalToVisualPos[(size_t)i] < 0)
|
||||||
|
m_logicalToVisualPos[(size_t)i] = last;
|
||||||
|
else
|
||||||
|
last = m_logicalToVisualPos[(size_t)i];
|
||||||
|
}
|
||||||
|
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
// PHASE 3: Render and build hyperlink ranges
|
// PHASE 3: Render and build hyperlink ranges
|
||||||
// ====================================================================
|
// ====================================================================
|
||||||
@@ -1431,10 +1457,6 @@ void CGraphicTextInstance::GetTextSize(int* pRetWidth, int* pRetHeight)
|
|||||||
|
|
||||||
int CGraphicTextInstance::PixelPositionToCharacterPosition(int iPixelPosition)
|
int CGraphicTextInstance::PixelPositionToCharacterPosition(int iPixelPosition)
|
||||||
{
|
{
|
||||||
// iPixelPosition is relative to the window
|
|
||||||
// Character positions in m_pCharInfoVector are relative to text start (0,0)
|
|
||||||
// We need to find which character the pixel falls on
|
|
||||||
|
|
||||||
// Clamp to valid range [0, textWidth]
|
// Clamp to valid range [0, textWidth]
|
||||||
int adjustedPixelPos = iPixelPosition;
|
int adjustedPixelPos = iPixelPosition;
|
||||||
if (adjustedPixelPos < 0)
|
if (adjustedPixelPos < 0)
|
||||||
@@ -1442,14 +1464,23 @@ int CGraphicTextInstance::PixelPositionToCharacterPosition(int iPixelPosition)
|
|||||||
if (adjustedPixelPos > m_textWidth)
|
if (adjustedPixelPos > m_textWidth)
|
||||||
adjustedPixelPos = m_textWidth;
|
adjustedPixelPos = m_textWidth;
|
||||||
|
|
||||||
// Find the character at the pixel position
|
// RTL: interpret click from right edge of rendered text
|
||||||
|
if (m_computedRTL)
|
||||||
|
adjustedPixelPos = m_textWidth - adjustedPixelPos;
|
||||||
|
|
||||||
int icurPosition = 0;
|
int icurPosition = 0;
|
||||||
int visualPos = -1;
|
int visualPos = -1;
|
||||||
|
|
||||||
for (int i = 0; i < (int)m_pCharInfoVector.size(); ++i)
|
for (int i = 0; i < (int)m_pCharInfoVector.size(); ++i)
|
||||||
{
|
{
|
||||||
CGraphicFontTexture::TCharacterInfomation* pCurCharInfo = m_pCharInfoVector[i];
|
CGraphicFontTexture::TCharacterInfomation* pCurCharInfo = m_pCharInfoVector[i];
|
||||||
icurPosition += pCurCharInfo->width;
|
|
||||||
|
// Use advance instead of width (width is not reliable for cursor hit-testing)
|
||||||
|
int adv = pCurCharInfo->advance;
|
||||||
|
if (adv <= 0)
|
||||||
|
adv = pCurCharInfo->width;
|
||||||
|
|
||||||
|
icurPosition += adv;
|
||||||
|
|
||||||
if (adjustedPixelPos < icurPosition)
|
if (adjustedPixelPos < icurPosition)
|
||||||
{
|
{
|
||||||
@@ -1458,11 +1489,9 @@ int CGraphicTextInstance::PixelPositionToCharacterPosition(int iPixelPosition)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found, use end position
|
|
||||||
if (visualPos < 0)
|
if (visualPos < 0)
|
||||||
visualPos = (int)m_pCharInfoVector.size();
|
visualPos = (int)m_pCharInfoVector.size();
|
||||||
|
|
||||||
// Convert visual position to logical position (accounting for tags)
|
|
||||||
if (!m_visualToLogicalPos.empty() && visualPos >= 0 && visualPos < (int)m_visualToLogicalPos.size())
|
if (!m_visualToLogicalPos.empty() && visualPos >= 0 && visualPos < (int)m_visualToLogicalPos.size())
|
||||||
return m_visualToLogicalPos[visualPos];
|
return m_visualToLogicalPos[visualPos];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user