WebCore:
authormjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Jan 2005 19:09:58 +0000 (19:09 +0000)
committermjs <mjs@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Jan 2005 19:09:58 +0000 (19:09 +0000)
        Reviewed by Darin.

<rdar://problem/3758033> REGRESSION (Mail): Support attributes in marked text (International input)

        * khtml/rendering/render_text.cpp:
        (InlineTextBox::paint): Support painting custom underline markers for
marked text in place of generic yellow.
        (InlineTextBox::paintMarkedTextUnderline): New method that handles this.
        * khtml/rendering/render_text.h:
        * kwq/KWQKHTMLPart.h: Declare new methods and structs.
        * kwq/KWQKHTMLPart.mm:
        (KWQKHTMLPart::clear): Clear marked test underlines.
        (KWQKHTMLPart::setMarkedTextRange): Takes attributes and ranges now.
        (convertAttributesToUnderlines): Converts NSAttributedString attributes
to simplified and C++-friendly form.
        (KWQKHTMLPart::markedTextUsesUnderlines): New method.
        (KWQKHTMLPart::markedTextUnderlines): New method.
        * kwq/KWQPainter.mm:
        (QPainter::drawLineForText): Handle pen width.
        * kwq/WebCoreBridge.h:
        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge setMarkedTextDOMRange:customAttributes:ranges:]): Take attributes
and ranges.
        * kwq/WebCoreTextRenderer.h:

WebKit:

        Reviewed by Darin.

<rdar://problem/3758033> REGRESSION (Mail): Support attributes in marked text (International input)

* WebCoreSupport.subproj/WebTextRenderer.m:
        (-[WebTextRenderer drawLineForCharacters:yOffset:width:color:thickness:]): Changed to support
underline thickness. Also added a bit of a hack here to move thickness 2 underlines down by
.5 pixels, since the rendering engine can't give a fractional pixel offset.
        * WebView.subproj/WebHTMLView.m:
        (-[WebHTMLView validAttributesForMarkedText]): Support underline, underline color and marked
clause attributes. Others that NSText supports are unimplemented for now.
        (-[WebHTMLView firstRectForCharacterRange:]): Remove needless logging.
        (-[WebHTMLView unmarkText]): Updated for new WebCore SPI.
        (-[WebHTMLView _extractAttributes:ranges:fromAttributedString:]): New method to pull the attributes
and ranges out of an attributed string.
        (-[WebHTMLView setMarkedText:selectedRange:]): Extract attributes and pass to WebCore.
        (-[WebHTMLView insertText:]): Add comment noting that we don't really handle attributed strings
here.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8360 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/rendering/render_text.cpp
WebCore/khtml/rendering/render_text.h
WebCore/kwq/KWQKHTMLPart.h
WebCore/kwq/KWQKHTMLPart.mm
WebCore/kwq/KWQPainter.mm
WebCore/kwq/WebCoreBridge.h
WebCore/kwq/WebCoreBridge.mm
WebCore/kwq/WebCoreTextRenderer.h
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebTextRenderer.m
WebKit/WebView.subproj/WebHTMLView.m

index 2693388f33d19308f3ebb43290fdf435b481d398..70e1c1803b3ae8ff25710b7913eb92f2b6dc4c70 100644 (file)
@@ -1,3 +1,30 @@
+2005-01-10  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Darin.
+
+       <rdar://problem/3758033> REGRESSION (Mail): Support attributes in marked text (International input)
+        
+        * khtml/rendering/render_text.cpp:
+        (InlineTextBox::paint): Support painting custom underline markers for
+       marked text in place of generic yellow.
+        (InlineTextBox::paintMarkedTextUnderline): New method that handles this.
+        * khtml/rendering/render_text.h:
+        * kwq/KWQKHTMLPart.h: Declare new methods and structs.
+        * kwq/KWQKHTMLPart.mm:
+        (KWQKHTMLPart::clear): Clear marked test underlines.
+        (KWQKHTMLPart::setMarkedTextRange): Takes attributes and ranges now.
+        (convertAttributesToUnderlines): Converts NSAttributedString attributes
+       to simplified and C++-friendly form.
+        (KWQKHTMLPart::markedTextUsesUnderlines): New method.
+        (KWQKHTMLPart::markedTextUnderlines): New method.
+        * kwq/KWQPainter.mm:
+        (QPainter::drawLineForText): Handle pen width.
+        * kwq/WebCoreBridge.h:
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge setMarkedTextDOMRange:customAttributes:ranges:]): Take attributes
+       and ranges.
+        * kwq/WebCoreTextRenderer.h:
+
 2005-01-12  David Harrison  <harrison@apple.com>
 
         Reviewed by Dave Hyatt.
index 1effd1e2373082284857c407c94a4ff358cc9916..e3a9b5607212ea6ea3217f0d9814e8786265cea6 100644 (file)
@@ -301,6 +301,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
     // Determine whether or not we have marked text.
     Range markedTextRange = KWQ(object()->document()->part())->markedTextRange();
     bool haveMarkedText = markedTextRange.handle() != 0 && markedTextRange.startContainer() == object()->node();
+    bool markedTextUsesUnderlines = KWQ(object()->document()->part())->markedTextUsesUnderlines();
+
 
     // Set our font.
     RenderStyle* styleToUse = object()->style(m_firstLine);
@@ -311,7 +313,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
 
     // 1. Paint backgrounds behind text if needed.  Examples of such backgrounds include selection
     // and marked text.
-    if ((haveSelection || haveMarkedText) && i.phase != PaintActionSelection && !isPrinting) {
+    if ((haveSelection || haveMarkedText) && !markedTextUsesUnderlines && i.phase != PaintActionSelection && !isPrinting) {
         if (haveMarkedText)
             paintMarkedTextBackground(i.p, tx, ty, styleToUse, font, markedTextRange.startOffset(), markedTextRange.endOffset());
 
@@ -324,6 +326,12 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
     QValueList<DocumentMarker> markers = object()->document()->markersForNode(object()->node());
     QValueListIterator <DocumentMarker> markerIt = markers.begin();
 
+    QValueList<KWQKHTMLPart::MarkedTextUnderline> underlines;
+    if (haveMarkedText && markedTextUsesUnderlines) {
+        underlines = KWQ(object()->document()->part())->markedTextUnderlines();
+    }
+    QValueListIterator<KWQKHTMLPart::MarkedTextUnderline> underlineIt = underlines.begin();
+
     QColor textColor = styleToUse->color();
     if (styleToUse->shouldCorrectTextColor())
         textColor = correctedTextColor(textColor, styleToUse->backgroundColor());
@@ -438,6 +446,30 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
                 // marker is completely after this run, bail.  A later run will paint it.
                 break;
         }
+
+
+        for ( ; underlineIt != underlines.end(); underlineIt++) {
+            KWQKHTMLPart::MarkedTextUnderline underline = *underlineIt;
+
+            if (underline.endOffset <= start())
+                // underline is completely before this run.  This might be an underlinethat sits
+                // before the first run we draw, or underlines that were within runs we skipped 
+                // due to truncation.
+                continue;
+            
+            if (underline.startOffset <= end()) {
+                // underline intersects this run.  Paint it.
+                paintMarkedTextUnderline(i.p, tx, ty, underline);
+                if (underline.endOffset > end() + 1)
+                    // underline also runs into the next run. Bail now, no more marker advancement.
+                    break;
+            } else
+                // underline is completely after this run, bail.  A later run will paint it.
+                break;
+        }
+
+
+
     }
 
     if (setShadow)
@@ -584,6 +616,41 @@ void InlineTextBox::paintMarker(QPainter *pt, int _tx, int _ty, DocumentMarker m
     pt->drawLineForMisspelling(_tx + start, _ty + underlineOffset, width);
 }
 
+void InlineTextBox::paintMarkedTextUnderline(QPainter *pt, int _tx, int _ty, KWQKHTMLPart::MarkedTextUnderline underline)
+{
+    _tx += m_x;
+    _ty += m_y;
+
+    if (m_truncation == cFullTruncation)
+        return;
+    
+    int start = 0;                  // start of line to draw, relative to _tx
+    int width = m_width;            // how much line to draw
+    bool useWholeWidth = true;
+    ulong paintStart = m_start;
+    ulong paintEnd = end()+1;      // end points at the last char, not past it
+    if (paintStart <= underline.startOffset) {
+        paintStart = underline.startOffset;
+        useWholeWidth = false;
+        start = static_cast<RenderText*>(m_object)->width(m_start, paintStart - m_start, m_firstLine);
+    }
+    if (paintEnd != underline.endOffset) {      // end points at the last char, not past it
+        paintEnd = kMin(paintEnd, (ulong)underline.endOffset);
+        useWholeWidth = false;
+    }
+    if (m_truncation != cNoTruncation) {
+        paintEnd = kMin(paintEnd, (ulong)m_truncation);
+        useWholeWidth = false;
+    }
+    if (!useWholeWidth) {
+        width = static_cast<RenderText*>(m_object)->width(paintStart, paintEnd - paintStart, m_firstLine);
+    }
+
+    int underlineOffset = m_height - 3;
+    pt->setPen(QPen(underline.color, underline.thick ? 2 : 0));
+    pt->drawLineForText(_tx + start, _ty, underlineOffset, width);
+}
+
 long InlineTextBox::caretMinOffset() const
 {
     return m_start;
index 00ae2a2800f6d50a13796155bb2ad1fb68ddbd3f..e0696f00eeb0ebca481a3a69a79cf80f2530941c 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <qptrvector.h>
 #include <assert.h>
+#include "KWQKHTMLPart.h"
 
 class QPainter;
 class QFontMetrics;
@@ -118,7 +119,7 @@ public:
     void paintSelection(QPainter* p, int tx, int ty, RenderStyle* style, const Font* font);
     void paintMarkedTextBackground(QPainter* p, int tx, int ty, RenderStyle* style, const Font* font, int startPos, int endPos);
     void paintMarker(QPainter* p, int _tx, int _ty, DOM::DocumentMarker marker);
-
+    void paintMarkedTextUnderline(QPainter *pt, int _tx, int _ty, KWQKHTMLPart::MarkedTextUnderline underline);
     virtual long caretMinOffset() const;
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
index 91780ea8bc9582c77c7c0fcd4a2b0c495c185b99..6d45d0d3fc30cead753ccdcf14fd4899ea1d95c7 100644 (file)
@@ -348,8 +348,23 @@ public:
     // Implementation of CSS property -khtml-user-drag == auto
     bool shouldDragAutoNode(DOM::NodeImpl*, int x, int y) const;
 
+    struct MarkedTextUnderline {
+        MarkedTextUnderline(unsigned _startOffset, unsigned _endOffset, const QColor &_color, bool _thick) 
+            : startOffset(_startOffset)
+            , endOffset(_endOffset)
+            , color(_color)
+            , thick(_thick)
+        {}
+        unsigned startOffset;
+        unsigned endOffset;
+        QColor color;
+        bool thick;
+    };
+    
+    void setMarkedTextRange(const DOM::Range &, NSArray *attributes, NSArray *ranges);
     DOM::Range markedTextRange() const;
-    void setMarkedTextRange(const DOM::Range &);
+    bool markedTextUsesUnderlines() const;
+    QValueList<MarkedTextUnderline> markedTextUnderlines() const;
 
     bool canGoBackOrForward(int distance) const;
 
@@ -448,6 +463,8 @@ private:
     mutable DOM::Node _elementToDraw;
 
     DOM::Range m_markedTextRange;
+    bool m_markedTextUsesUnderlines;
+    QValueList<MarkedTextUnderline> m_markedTextUnderlines;
 };
 
 inline KWQKHTMLPart *KWQ(KHTMLPart *part) { return static_cast<KWQKHTMLPart *>(part); }
index 438b7d7f6e85b67dfb7acc5f7c77f322cee3cab9..d8538284c33d6ae7c78022f4b6492d96f8dcdd2a 100644 (file)
@@ -3756,7 +3756,7 @@ bool KWQKHTMLPart::haveToldBridgeAboutLoad(const QString &urlString)
 void KWQKHTMLPart::clear()
 {
     urlsBridgeKnowsAbout.clear();
-    setMarkedTextRange(0);
+    setMarkedTextRange(0, nil, nil);
     KHTMLPart::clear();
 }
 
@@ -4024,11 +4024,52 @@ DOM::Range KWQKHTMLPart::markedTextRange() const
     return m_markedTextRange;
 }
 
-void KWQKHTMLPart::setMarkedTextRange(const DOM::Range &range)
+static QValueList<KWQKHTMLPart::MarkedTextUnderline> convertAttributesToUnderlines(const DOM::Range &markedTextRange, NSArray *attributes, NSArray *ranges)
+{
+    QValueList<KWQKHTMLPart::MarkedTextUnderline> result;
+
+    int baseOffset = markedTextRange.startOffset();
+
+    unsigned length = [attributes count];
+    ASSERT([ranges count] == length);
+
+    for (unsigned i = 0; i < length; i++) {
+        NSNumber *style = [[attributes objectAtIndex:i] objectForKey:NSUnderlineStyleAttributeName];
+        if (!style)
+            continue;
+        NSRange range = [[ranges objectAtIndex:i] rangeValue];
+        NSColor *color = [[attributes objectAtIndex:i] objectForKey:NSUnderlineColorAttributeName];
+        QColor qColor = Qt::black;
+        if (color) {
+            NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
+            qColor = QColor(qRgba((int)(255 * [deviceColor redComponent]),
+                                  (int)(255 * [deviceColor blueComponent]),
+                                  (int)(255 * [deviceColor greenComponent]),
+                                  (int)(255 * [deviceColor alphaComponent])));
+        }
+
+        result.append(KWQKHTMLPart::MarkedTextUnderline(range.location + baseOffset, 
+                                                        range.location + baseOffset + range.length, 
+                                                        qColor,
+                                                        [style intValue] > 1));
+    }
+
+    return result;
+}
+
+void KWQKHTMLPart::setMarkedTextRange(const DOM::Range &range, NSArray *attributes, NSArray *ranges)
 {
     ASSERT(!range.handle() || range.startContainer() == range.endContainer());
     ASSERT(!range.handle() || range.collapsed() || range.startContainer().nodeType() == Node::TEXT_NODE);
 
+    if (attributes == nil) {
+        m_markedTextUsesUnderlines = false;
+        m_markedTextUnderlines.clear();
+    } else {
+        m_markedTextUsesUnderlines = true;
+        m_markedTextUnderlines = convertAttributesToUnderlines(range, attributes, ranges);
+    }
+
     if (m_markedTextRange.handle() && xmlDocImpl() 
        && m_markedTextRange.startContainer().handle()->renderer()) {
        m_markedTextRange.startContainer().handle()->renderer()->repaint();
@@ -4046,6 +4087,16 @@ void KWQKHTMLPart::setMarkedTextRange(const DOM::Range &range)
     }
 }
 
+bool KWQKHTMLPart::markedTextUsesUnderlines() const
+{
+    return m_markedTextUsesUnderlines;
+}
+
+QValueList<KWQKHTMLPart::MarkedTextUnderline> KWQKHTMLPart::markedTextUnderlines() const
+{
+    return m_markedTextUnderlines;
+}
+
 bool KWQKHTMLPart::canGoBackOrForward(int distance) const
 {
     return [_bridge canGoBackOrForward:distance];
index f01014a8fcc3e44fdef3dfa6e167e9db63afd8b6..7b871c11357fdf077d1d52858cd110dda511bbdf 100644 (file)
@@ -712,8 +712,9 @@ void QPainter::drawLineForText(int x, int y, int yOffset, int width)
     [data->textRenderer
         drawLineForCharacters: NSMakePoint(x, y)
                yOffset:(float)yOffset
-             withWidth: width
-             withColor:data->state.pen.color().getNSColor()];
+                 width: width
+                 color:data->state.pen.color().getNSColor()
+             thickness:data->state.pen.width()];
 }
 
 void QPainter::drawLineForMisspelling(int x, int y, int width)
index aebfadc49dc8b38e0c5b071e0961aa7df020105f..deb68473bf4b84e1e56db16aa58651fc3666aeac 100644 (file)
@@ -322,8 +322,8 @@ typedef enum {
 - (void)setMarkDOMRange:(DOMRange *)range;
 - (DOMRange *)markDOMRange;
 
-// spelling-checking "marked text"
-- (void)setMarkedTextDOMRange:(DOMRange *)range;
+// international text input "marked text"
+- (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges;
 - (DOMRange *)markedTextDOMRange;
 
 - (NSAttributedString *)attributedStringFrom:(DOMNode *)startNode startOffset:(int)startOffset to:(DOMNode *)endNode endOffset:(int)endOffset;
index 1062118100806f6ee4663db500ce84f23f84f7d7..8c80daeef3bdec0c662c77f575e4ea20412635df 100644 (file)
@@ -1547,9 +1547,9 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     return [DOMRange _rangeWithImpl:_part->mark().toRange().handle()];
 }
 
-- (void)setMarkedTextDOMRange:(DOMRange *)range
+- (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
 {
-    _part->setMarkedTextRange([range _rangeImpl]);
+    _part->setMarkedTextRange([range _rangeImpl], attributes, ranges);
 }
 
 - (DOMRange *)markedTextDOMRange
index 4075beb24b8130381c298bd7594ad5f8013cfbce..a948f119fb727c2e6cf841ea96731e94a41e1baa 100644 (file)
@@ -97,7 +97,7 @@ extern void WebCoreInitializeEmptyTextGeometry(WebCoreTextGeometry *geometry);
 // drawing
 - (void)drawRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
 - (void)drawHighlightForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
-- (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset withWidth:(int)width withColor:(NSColor *)color;
+- (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset width: (int)width color:(NSColor *)color thickness:(float)thickness;
 - (void)drawLineForMisspelling:(NSPoint)point withWidth:(int)width;
 
 // selection point check
index be38146f23aafac68b80fe8b9f441b54ddcb6ea8..db89ad6f913bbd4dd58534d44e9f5e220c4d5640 100644 (file)
@@ -1,3 +1,24 @@
+2005-01-10  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Darin.
+
+       <rdar://problem/3758033> REGRESSION (Mail): Support attributes in marked text (International input)
+        
+       * WebCoreSupport.subproj/WebTextRenderer.m:
+        (-[WebTextRenderer drawLineForCharacters:yOffset:width:color:thickness:]): Changed to support
+       underline thickness. Also added a bit of a hack here to move thickness 2 underlines down by
+       .5 pixels, since the rendering engine can't give a fractional pixel offset.
+        * WebView.subproj/WebHTMLView.m:
+        (-[WebHTMLView validAttributesForMarkedText]): Support underline, underline color and marked
+       clause attributes. Others that NSText supports are unimplemented for now.
+        (-[WebHTMLView firstRectForCharacterRange:]): Remove needless logging.
+        (-[WebHTMLView unmarkText]): Updated for new WebCore SPI.
+        (-[WebHTMLView _extractAttributes:ranges:fromAttributedString:]): New method to pull the attributes
+       and ranges out of an attributed string.
+        (-[WebHTMLView setMarkedText:selectedRange:]): Extract attributes and pass to WebCore.
+        (-[WebHTMLView insertText:]): Add comment noting that we don't really handle attributed strings
+       here.
+
 2005-01-12  Darin Adler  <darin@apple.com>
 
         Reviewed by Ken.
index 6715538135e11dce362a5cb66e4c1e1f54350f56..170f593e5b2505317517aaf48461b54c358e8ff4 100644 (file)
@@ -536,10 +536,8 @@ static BOOL alwaysUseATSU = NO;
     return [self _floatWidthForRun:run style:style widths:widthBuffer fonts:nil glyphs:nil startPosition:nil numGlyphs:nil];
 }
 
-- (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset withWidth: (int)width withColor:(NSColor *)color
+- (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset width: (int)width color:(NSColor *)color thickness:(float)thickness
 {
-    // XXX MJS
-
     NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext];
     CGContextRef cgContext;
 
@@ -550,6 +548,8 @@ static BOOL alwaysUseATSU = NO;
     
     BOOL flag = [graphicsContext shouldAntialias];
 
+    [graphicsContext setShouldAntialias: NO];
+
     // We don't want antialiased lines on screen, but we do when printing (else they are too thick)
     if ([graphicsContext isDrawingToScreen]) {
         [graphicsContext setShouldAntialias:NO];
@@ -558,8 +558,19 @@ static BOOL alwaysUseATSU = NO;
     [color set];
 
     cgContext = (CGContextRef)[graphicsContext graphicsPort];
-    CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
-    CGContextSetLineWidth(cgContext, size.width);
+
+    // hack to make thickness 2 underlines for internation text input look right
+    if (thickness > 1.5 && thickness < 2.5) {
+        yOffset += .5;
+    }
+
+    if (thickness == 0.0) {
+        CGSize size = CGSizeApplyAffineTransform(CGSizeMake(1.0, 1.0), CGAffineTransformInvert(CGContextGetCTM(cgContext)));
+        CGContextSetLineWidth(cgContext, size.width);
+    } else {
+        CGContextSetLineWidth(cgContext, thickness);
+    }
+
 
 #if BUILDING_ON_PANTHER            
     CGContextMoveToPoint(cgContext, point.x, point.y + [self lineSpacing] + 1.5 - [self descent] + yOffset);
index f9ed94e59e4d80ae64fd3f390018e9c675aaafca..29ceda39b3bfdfb2ac98f669194579697d85b6b6 100644 (file)
@@ -58,6 +58,9 @@
 // <rdar://problem/3630640>: "Calling interpretKeyEvents: in a custom text view can fail to process keys right after app startup"
 #import <AppKit/NSKeyBindingManager.h>
 
+// need to declare this because AppKit does not make it available as API or SPI
+extern NSString *NSMarkedClauseSegmentAttributeName; 
+
 // Kill ring calls. Would be better to use NSKillRing.h, but that's not available in SPI.
 void _NSInitializeKillRing(void);
 void _NSAppendToKillRing(NSString *);
@@ -4333,10 +4336,22 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
 
 @implementation WebHTMLView (WebNSTextInputSupport)
 
+static NSArray *validAttributes = nil;
+
 - (NSArray *)validAttributesForMarkedText
 {
-    // FIXME: TEXTINPUT: validAttributesForMarkedText not yet implemented
-    return [NSArray array];
+    if (!validAttributes) {
+        validAttributes = [[NSArray allocWithZone:[self zone]] initWithObjects:NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName, NSMarkedClauseSegmentAttributeName, nil];
+        // NSText also supports the following attributes, but it's
+        // hard to tell which are really required for text input to
+        // work well; I have not seen any input method make use of them yet.
+        //
+        // NSFontAttributeName, NSForegroundColorAttributeName,
+        // NSBackgroundColorAttributeName, NSLanguageAttributeName,
+        // NSTextInputReplacementRangeAttributeName
+    }
+
+    return validAttributes;
 }
 
 - (unsigned int)characterIndexForPoint:(NSPoint)thePoint
@@ -4347,8 +4362,6 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
 
 - (NSRect)firstRectForCharacterRange:(NSRange)theRange
 {
-    NSLog(@"location: %d  length: %d\n", theRange.location, theRange.length);
-
     if (![self hasMarkedText]) {
         return NSMakeRect(0,0,0,0);
     }
@@ -4363,8 +4376,6 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
     NSRect resultRect = [self convertRect:[bridge firstRectForDOMRange:rectRange] toView:nil];
     resultRect.origin = [[self window] convertBaseToScreen:resultRect.origin];
 
-    NSLog(@"(%d,%d) %dx%d\n", (int)resultRect.origin.x, (int)resultRect.origin.y, (int)resultRect.size.width, (int)resultRect.size.height);
-
     return resultRect;
 }
 
@@ -4406,7 +4417,7 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
 
 - (void)unmarkText
 {
-    [[self _bridge] setMarkedTextDOMRange:nil];
+    [[self _bridge] setMarkedTextDOMRange:nil customAttributes:nil ranges:nil];
 }
 
 - (void)_selectMarkedText
@@ -4437,6 +4448,23 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
     [bridge setSelectedDOMRange:selectedRange affinity:NSSelectionAffinityUpstream];
 }
 
+- (void)_extractAttributes:(NSArray **)a ranges:(NSArray **)r fromAttributedString:(NSAttributedString *)string
+{
+        int length = [[string string] length];
+        int i = 0;
+        NSMutableArray *attributes = [NSMutableArray array];
+        NSMutableArray *ranges = [NSMutableArray array];
+        while (i < length) {
+            NSRange effectiveRange;
+            NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&effectiveRange inRange:NSMakeRange(i,length - i)];
+            [attributes addObject:attrs];
+            [ranges addObject:[NSValue valueWithRange:effectiveRange]];
+            i = effectiveRange.location + effectiveRange.length;
+       }
+        *a = attributes;
+        *r = ranges;
+}
+
 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange
 {
     WebBridge *bridge = [self _bridge];
@@ -4451,15 +4479,17 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
     [self _selectMarkedText];
 
     NSString *text;
+    NSArray *attributes = nil;
+    NSArray *ranges = nil;
     if ([string isKindOfClass:[NSAttributedString class]]) {
-       ERROR("TEXTINPUT: requested set marked text with attributed string");
        text = [string string];
+        [self _extractAttributes:&attributes ranges:&ranges fromAttributedString:string];
     } else {
        text = string;
     }
 
     [bridge replaceSelectionWithText:text selectReplacement:YES smartReplace:NO];
-    [bridge setMarkedTextDOMRange:[self _selectedRange]];
+    [bridge setMarkedTextDOMRange:[self _selectedRange] customAttributes:attributes ranges:ranges];
     if ([self hasMarkedText]) {
         [self _selectRangeInMarkedText:newSelRange];
     }
@@ -4519,19 +4549,13 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
 {
     NSString *text;
     if ([string isKindOfClass:[NSAttributedString class]]) {
-       ERROR("TEXTINPUT: requested insert of attributed string");
        text = [string string];
-        int length = [text length];
-        int i = 0;
-        while (i < length) {
-            NSRange effectiveRange;
-            NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&effectiveRange inRange:NSMakeRange(i,length - i)];
-            i = effectiveRange.location + effectiveRange.length;
-            NSLog(@"attribute chunk: %@ from %d length %d\n", attrs, effectiveRange.location, effectiveRange.length);
-       }
+        // we don't yet support inserting an attributed string but input methods
+        // don't appear to require this.
     } else {
        text = string;
     }
+
     [self _insertText:text selectInsertedText:NO];
 }