patch: khtml text selection with complex text

Simon Hausmann hausmann at kde.org
Sun Mar 12 21:34:50 GMT 2006


Hi,

text selection with complex text is currently broken in khtml, because khtml 
draws the selected text as a separate string, breaking it apart at invalid 
positions. You can see that easily on web sites with arabic text for example. 
The only solution to that problem is unfortunately to draw the run of text 
that is part of the beginning or the end of the selection twice, once 
unselected and once selected with a clip rectangle set. The clipping is 
necessary as there may be valid cursor positions inside a ligature.

Attached is my attempt at implementing this. Would be cool if somebody could 
comment on the patch, or perhaps even approve it :)

Thanks,
Simon
-------------- next part --------------
Index: render_text.cpp
===================================================================
--- render_text.cpp	(revision 517934)
+++ render_text.cpp	(working copy)
@@ -140,10 +140,29 @@
     p->setPen(hc);
 
     //kdDebug( 6040 ) << "textRun::painting(" << QConstString(text->str->s + m_start, m_len).string().left(30) << ") at(" << m_x+tx << "/" << m_y+ty << ")" << endl;
+
+    p->save();
+
+    int visualSelectionStart = f->width(text->str->s, text->str->l, m_start, startPos);
+    int visualSelectionEnd = f->width(text->str->s, text->str->l, m_start, endPos);
+    int visualSelectionWidth = visualSelectionEnd - visualSelectionStart;
+    if (m_reversed) {
+        visualSelectionStart = f->width(text->str->s, text->str->l, m_start, m_len) - visualSelectionEnd;
+    }
+
+    QRect selectionRect(m_x + tx + visualSelectionStart, m_y + ty, visualSelectionWidth, height());
+    QRegion r(selectionRect);
+    if (p->hasClipping())
+        r &= p->clipRegion(QPainter::CoordPainter);
+    p->setClipRegion(r, QPainter::CoordPainter);
+    p->fillRect(selectionRect, hbg);
+
     f->drawText(p, m_x + tx, m_y + ty + m_baseline, text->str->s, text->str->l,
-    		m_start, m_len, m_toAdd,
-		m_reversed ? QPainter::RTL : QPainter::LTR,
-		startPos, endPos, hbg, m_y + ty, height(), deco);
+                m_start, m_len, m_toAdd,
+                m_reversed ? QPainter::RTL : QPainter::LTR,
+                -1, -1, hbg, m_y + ty, height(), deco);
+
+    p->restore();
 }
 
 void InlineTextBox::paintDecoration( QPainter *pt, const Font *f, int _tx, int _ty, int deco)
@@ -923,54 +942,13 @@
 #endif
 
             if (s->m_len > 0 && pI.phase != PaintActionSelection) {
-	        if (!haveSelection) {
-	            //kdDebug( 6040 ) << "RenderObject::paintObject(" << QConstString(str->s + s->m_start, s->m_len).string() << ") at(" << s->m_x+tx << "/" << s->m_y+ty << ")" << endl;
-#ifndef APPLE_CHANGES
-                    if (_style->textShadow())
-                        s->paintShadow(pI.p, font, tx, ty, _style->textShadow());
-#endif
+                //kdDebug( 6040 ) << "RenderObject::paintObject(" << QConstString(str->s + s->m_start, s->m_len).string() << ") at(" << s->m_x+tx << "/" << s->m_y+ty << ")" << endl;
+                if (_style->textShadow())
+                    s->paintShadow(pI.p, font, tx, ty, _style->textShadow());
 // kdDebug(6040) << QConstString(str->s + s->m_start, s->m_len).string().left(40) << endl;
-		    font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s, str->l, s->m_start, s->m_len,
-				   s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR);
-	        }
-		else {
-                    int offset = s->m_start;
-                    int sPos = kMax( startPos - offset, 0 );
-                    int ePos = kMin( endPos - offset, int( s->m_len ) );
-// selected text is always separate in konqueror
-#ifdef APPLE_CHANGES
-                    if (paintSelectedTextSeparately) {
-#endif
-#ifndef APPLE_CHANGES
-                        if (_style->textShadow())
-                            s->paintShadow(pI.p, font, tx, ty, _style->textShadow());
-#endif
-                        if (sPos >= ePos)
-                            font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline,
-                                           str->s, str->l, s->m_start, s->m_len,
-                                           s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR);
-                        else {
-                            if (sPos-1 >= 0)
-                                font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline,
-                                               str->s, str->l, s->m_start, s->m_len,
-                                               s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, 0, sPos);
-                            if (ePos < s->m_len)
-                                font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline,
-                                               str->s, str->l, s->m_start, s->m_len,
-                                               s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, ePos, s->m_len);
-                        }
-#ifdef APPLE_CHANGES
-                    }
-
-                    if ( sPos < ePos ) {
-                        if (selectionColor != p->pen().color())
-                            p->setPen(selectionColor);
-
-                        font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s,
-                                       str->l, s->m_start, s->m_len,
-                                       s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, sPos, ePos);
-                    }
-#endif
+                if (!haveSelection || startPos != s->m_start || endPos != s->m_start + s->m_len) {
+                    font->drawText(pI.p, s->m_x + tx, s->m_y + ty + s->m_baseline, str->s, str->l, s->m_start, s->m_len,
+                                   s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR);
                 }
 	    }
 


More information about the kfm-devel mailing list