Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a few text selection issues #607

Merged
merged 3 commits into from
Nov 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 52 additions & 6 deletions crengine/src/lvtinydom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,20 @@ lUInt32 calcGlobalSettingsHash(int documentId, bool already_rendered)
hash = hash * 31 + HyphMan::getTrustSoftHyphens();
hash = hash * 31 + UserHyphDict::getHash();
}
/*
printf(" %d %d %d %d %d %d %d %d %d %d %d\n",
(int)fontMan->GetKerningMode(),
fontMan->GetMonospaceSizeScale(),
(int)fontMan->GetFallbackFontSizesAdjusted(),
fontMan->GetFontListHash(documentId),
LVRendGetBaseFontWeight(),
gRenderDPI,
TextLangMan::getHash(),
HyphMan::getLeftHyphenMin(),
HyphMan::getRightHyphenMin(),
HyphMan::getTrustSoftHyphens(),
UserHyphDict::getHash());
*/
return hash;
}

Expand Down Expand Up @@ -9745,10 +9759,16 @@ ldomXPointer ldomDocument::createXPointer( lvPoint pt, int direction, bool stric
return ldomXPointer(node, 0);
}
// It is a word
if ( find_first ) // return xpointer to logical start of word
if ( find_first ) { // return xpointer to logical start of word
if ( node->isElement() ) // (see comment about <br/><br/> below)
return ldomXPointer(node, 0);
return ldomXPointer( node, src->t.offset + word->t.start );
else // return xpointer to logical end of word
}
else { // return xpointer to logical end of word
if ( node->isElement() )
return ldomXPointer(node, 0);
return ldomXPointer( node, src->t.offset + word->t.start + word->t.len );
}
}

// Found line, searching for word (words are in visual order)
Expand Down Expand Up @@ -9827,24 +9847,36 @@ ldomXPointer ldomDocument::createXPointer( lvPoint pt, int direction, bool stric
font->measureText( str.c_str()+word->t.start, word->t.len, width, flg, word->width+50, '?',
src->lang_cfg, src->letter_spacing + word->added_letter_spacing, false, hints);

// In some special cases, node may be an element and not a text node (ie. on a blank
// line caused by <br/><br/> where our word is a space generated by lvrend): below,
// we must return node with an offset of 0 (to avoid getting xpointer like p[2]/br[3].1
// which may fail being resolved back to the br node).
bool word_is_rtl = word->flags & LTEXT_WORD_DIRECTION_IS_RTL;
if ( word_is_rtl ) {
for ( int i=word->t.len-1; i>=0; i-- ) {
int xx = ( i>0 ) ? (width[i-1] + width[i])/2 : width[i]/2;
xx = word->width - xx;
if ( x < word->x + xx ) {
if ( node->isElement() )
return ldomXPointer(node, 0);
return ldomXPointer( node, src->t.offset + word->t.start + i );
}
}
if ( node->isElement() )
return ldomXPointer(node, 0);
return ldomXPointer( node, src->t.offset + word->t.start );
}
else {
for ( int i=0; i<word->t.len; i++ ) {
int xx = ( i>0 ) ? (width[i-1] + width[i])/2 : width[i]/2;
if ( x < word->x + xx ) {
if ( node->isElement() )
return ldomXPointer(node, 0);
return ldomXPointer( node, src->t.offset + word->t.start + i );
}
}
if ( node->isElement() )
return ldomXPointer( node, 0 );
return ldomXPointer( node, src->t.offset + word->t.start + word->t.len );
}
}
Expand Down Expand Up @@ -10442,6 +10474,16 @@ bool ldomXPointer::getRect(lvRect & rect, bool extended, bool adjusted) const
}
}
}
if ( frmline->word_count == 0 && l == txtform->GetLineCount() - 1 && frmline->height == 0 ) {
// Handle a special case: we may end up setting the last added line a height of
// zero when we realize no word would be added. We don't want to return the full
// final node.
rect.left = rc.left;
rect.top = rc.top + frmline->y;
rect.right = rect.left + 1; // not the right word: no char width
rect.bottom = rect.top + frmline->height + 1;
return true;
}
}
// return false;
// Not found, which is possible with a final node with only empty
Expand Down Expand Up @@ -12346,6 +12388,7 @@ void ldomXRange::getSegmentRects( LVArray<lvRect> & rects, bool includeImages )
// we only deal with text nodes (and optionally images): get the first
go_on = includeImages ? curPos.nextTextOrImage() : curPos.nextText();

bool is_whitespace_pre = false;
while (go_on) { // new line or new/continued text node
// We may have (empty or not if not yet pushed) from previous iteration:
// lineStartRect : char rect for first char of line, even if from another text node
Expand Down Expand Up @@ -12400,11 +12443,13 @@ void ldomXRange::getSegmentRects( LVArray<lvRect> & rects, bool includeImages )
continue;
}
}
ldomNode * parent = curPos.getNode()->getParentNode();
is_whitespace_pre = !parent->getStyle().isNull() && parent->getStyle()->white_space >= css_ws_pre_line;
}
// Skip space at start of node or at start of new line
// (the XML parser made sure we always have a single space
// at boundaries)
if (nodeText[startOffset] == ' ') {
if (nodeText[startOffset] == ' ' && !is_whitespace_pre) {
startOffset += 1;
nodeStartRect = lvRect(); // reset
}
Expand Down Expand Up @@ -12473,7 +12518,7 @@ void ldomXRange::getSegmentRects( LVArray<lvRect> & rects, bool includeImages )

// 2) Look if the full text node is contained on the line
// Ignore (possibly collapsed) space at end of text node
curPos.setOffset(nodeText[textLen-1] == ' ' ? textLen-2 : textLen-1 );
curPos.setOffset(nodeText[textLen-1] == ' ' && !is_whitespace_pre ? textLen-2 : textLen-1);
curCharRect = lvRect();
if (!curPos.getRectEx(curCharRect, true)) {
// printf("#### curPos.getRectEx(textLen=%d) failed\n", textLen);
Expand All @@ -12499,9 +12544,10 @@ void ldomXRange::getSegmentRects( LVArray<lvRect> & rects, bool includeImages )
// skip spaces (but let soft-hyphens in, so they are part of the
// highlight when they are shown at end of line)
lChar32 c = nodeText[i];
if (c == ' ') // || c == 0x00AD)
continue;
curPos.setOffset(i);
if (c == ' ' && !is_whitespace_pre) { // || c == 0x00AD)
continue;
}
curCharRect = lvRect(); // reset
if (!curPos.getRectEx(curCharRect, true)) {
// printf("#### curPos.getRectEx(char=%d) failed\n", i);
Expand Down
Loading