Commit 6b99ea1e authored by sullivan's avatar sullivan

Reviewed by Tim Omernick and Dave Hyatt.

        WebCore support for computing but not highlighting rects for text matches.

        * dom/Document.h:
        added setRenderedRectForMarker() and renderedRectsForMarkers(), and redefined
        MarkerMap to be a hashtable of node -> (pair of vectors), one vector of markers
        and one vector of rects
        
        * dom/Document.cpp:
        (placeholderRectForMarker()):
        new function, returns a recognizable degenerate rect used until a real rect has been set
        (WebCore::Document::addMarker):
        Reworked for new MarkerMap data structure; now adds parallel placeholder rect
        along with marker
        (WebCore::Document::copyMarkers):
        Reworked for new MarkerMap data structure
        (WebCore::Document::removeMarkers):
        Reworked for new MarkerMap data structure; now removed corresponding rect along
        with marker
        (WebCore::Document::markersForNode):
        Reworked for new MarkerMap data structure
        (WebCore::Document::renderedRectsForMarkers):
        New method, returns an array of all non-placeholder rects for the given marker type
        (WebCore::Document::repaintMarkers):
        Reworked for new MarkerMap data structure
        (WebCore::Document::setRenderedRectForMarker):
        New method, sets the rendered rect for a given marker
        (WebCore::Document::shiftMarkers):
        Reworked for new MarkerMap data structure; resets rendered rects to placeholders.
        
        * rendering/InlineTextBox.cpp:
        (WebCore::InlineTextBox::paint):
        removed markedTextMatchesAreHighlighted guard; we always want to call paintTextMatchMarker
        now, but sometimes we will end up only computing the rect, not actually highlighting it.
        (Maybe some names should be improved here?)
        (WebCore::InlineTextBox::paintTextMatchMarker):
        Reorganized to move all the code that actually draws into a block that's guarded by
        markedTextMatchesAreHighlighted. The rest of the code computes where the highlight will
        go, and now we always use that computation in order to call setRenderedRectForMarker.

        * bridge/mac/WebCoreFrameBridge.h:
        * bridge/mac/WebCoreFrameBridge.mm:
        (-[WebCoreFrameBridge rectsForTextMatches]):
        New method, returns an array of NSValues representing NSRects. Gets them
        from Document::renderedRectsForMarkers



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@14805 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent f99d1e82
2006-06-09 John Sullivan <sullivan@apple.com>
Reviewed by Tim Omernick and Dave Hyatt.
WebCore support for computing but not highlighting rects for text matches.
* dom/Document.h:
added setRenderedRectForMarker() and renderedRectsForMarkers(), and redefined
MarkerMap to be a hashtable of node -> (pair of vectors), one vector of markers
and one vector of rects
* dom/Document.cpp:
(placeholderRectForMarker()):
new function, returns a recognizable degenerate rect used until a real rect has been set
(WebCore::Document::addMarker):
Reworked for new MarkerMap data structure; now adds parallel placeholder rect
along with marker
(WebCore::Document::copyMarkers):
Reworked for new MarkerMap data structure
(WebCore::Document::removeMarkers):
Reworked for new MarkerMap data structure; now removed corresponding rect along
with marker
(WebCore::Document::markersForNode):
Reworked for new MarkerMap data structure
(WebCore::Document::renderedRectsForMarkers):
New method, returns an array of all non-placeholder rects for the given marker type
(WebCore::Document::repaintMarkers):
Reworked for new MarkerMap data structure
(WebCore::Document::setRenderedRectForMarker):
New method, sets the rendered rect for a given marker
(WebCore::Document::shiftMarkers):
Reworked for new MarkerMap data structure; resets rendered rects to placeholders.
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::paint):
removed markedTextMatchesAreHighlighted guard; we always want to call paintTextMatchMarker
now, but sometimes we will end up only computing the rect, not actually highlighting it.
(Maybe some names should be improved here?)
(WebCore::InlineTextBox::paintTextMatchMarker):
Reorganized to move all the code that actually draws into a block that's guarded by
markedTextMatchesAreHighlighted. The rest of the code computes where the highlight will
go, and now we always use that computation in order to call setRenderedRectForMarker.
* bridge/mac/WebCoreFrameBridge.h:
* bridge/mac/WebCoreFrameBridge.mm:
(-[WebCoreFrameBridge rectsForTextMatches]):
New method, returns an array of NSValues representing NSRects. Gets them
from Document::renderedRectsForMarkers
2006-06-10 Anders Carlsson <acarlsson@apple.com>
Reviewed by Eric.
......
......@@ -311,6 +311,7 @@ typedef enum {
- (BOOL)markedTextMatchesAreHighlighted;
- (void)setMarkedTextMatchesAreHighlighted:(BOOL)doHighlight;
- (void)unmarkAllTextMatches;
- (NSArray *)rectsForTextMatches;
- (NSString *)advanceToNextMisspelling;
- (NSString *)advanceToNextMisspellingStartingJustBeforeSelection;
......
......@@ -1212,6 +1212,21 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
doc->removeMarkers(DocumentMarker::TextMatch);
}
- (NSArray *)rectsForTextMatches
{
Document *doc = m_frame->document();
if (!doc)
return [NSArray array];
NSMutableArray *result = [NSMutableArray array];
Vector<IntRect> rects = doc->renderedRectsForMarkers(DocumentMarker::TextMatch);
unsigned count = rects.size();
for (unsigned index = 0; index < count; ++index)
[result addObject:[NSValue valueWithRect:rects[index]]];
return result;
}
- (NSString *)advanceToNextMisspelling
{
return m_frame->advanceToNextMisspelling();
......
......@@ -2630,6 +2630,10 @@ String Document::queryCommandValue(const String &command)
return jsEditor()->queryCommandValue(command);
}
static IntRect placeholderRectForMarker(void)
{
return IntRect(-1,-1,-1,-1);
}
void Document::addMarker(Range *range, DocumentMarker::MarkerType type)
{
......@@ -2663,14 +2667,19 @@ void Document::addMarker(Node *node, DocumentMarker newMarker)
if (newMarker.endOffset == newMarker.startOffset)
return;
Vector<DocumentMarker>* markers = m_markers.get(node);
if (!markers) {
markers = new Vector<DocumentMarker>;
markers->append(newMarker);
m_markers.set(node, markers);
MarkerMapVectorPair* vectorPair = m_markers.get(node);
if (!vectorPair) {
vectorPair = new MarkerMapVectorPair;
vectorPair->first.append(newMarker);
vectorPair->second.append(placeholderRectForMarker());
m_markers.set(node, vectorPair);
} else {
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<IntRect>& rects = vectorPair->second;
ASSERT(markers.size() == rects.size());
Vector<DocumentMarker>::iterator it;
for (it = markers->begin(); it != markers->end();) {
for (it = markers.begin(); it != markers.end();) {
DocumentMarker marker = *it;
if (newMarker.endOffset < marker.startOffset+1) {
......@@ -2688,12 +2697,14 @@ void Document::addMarker(Node *node, DocumentMarker newMarker)
newMarker.startOffset = min(newMarker.startOffset, marker.startOffset);
newMarker.endOffset = max(newMarker.endOffset, marker.endOffset);
// remove old one, we'll add newMarker later
markers->remove(it - markers->begin());
markers.remove(it - markers.begin());
rects.remove(it - markers.begin());
// it points to the next marker to consider
}
}
// at this point it points to the node before which we want to insert
markers->insert(it - markers->begin(), newMarker);
markers.insert(it - markers.begin(), newMarker);
rects.insert(it - markers.begin(), placeholderRectForMarker());
}
// repaint the affected node
......@@ -2708,14 +2719,17 @@ void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node
if (length <= 0)
return;
Vector<DocumentMarker>* markers = m_markers.get(srcNode);
if (!markers)
MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
if (!vectorPair)
return;
ASSERT(vectorPair->first.size() == vectorPair->second.size());
bool docDirty = false;
unsigned endOffset = startOffset + length - 1;
Vector<DocumentMarker>::iterator it;
for (it = markers->begin(); it != markers->end(); ++it) {
Vector<DocumentMarker>& markers = vectorPair->first;
for (it = markers.begin(); it != markers.end(); ++it) {
DocumentMarker marker = *it;
// stop if we are now past the specified range
......@@ -2748,14 +2762,17 @@ void Document::removeMarkers(Node *node, unsigned startOffset, int length, Docum
if (length <= 0)
return;
Vector<DocumentMarker>* markers = m_markers.get(node);
if (!markers)
MarkerMapVectorPair* vectorPair = m_markers.get(node);
if (!vectorPair)
return;
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<IntRect>& rects = vectorPair->second;
ASSERT(markers.size() == rects.size());
bool docDirty = false;
unsigned endOffset = startOffset + length - 1;
Vector<DocumentMarker>::iterator it;
for (it = markers->begin(); it < markers->end();) {
for (it = markers.begin(); it < markers.end();) {
DocumentMarker marker = *it;
// markers are returned in order, so stop if we are now past the specified range
......@@ -2771,30 +2788,34 @@ void Document::removeMarkers(Node *node, unsigned startOffset, int length, Docum
// at this point we know that marker and target intersect in some way
docDirty = true;
// pitch the old marker
markers->remove(it - markers->begin());
// pitch the old marker and any associated rect
markers.remove(it - markers.begin());
rects.remove(it - markers.begin());
// it now points to the next node
// add either of the resulting slices that are left after removing target
if (startOffset > marker.startOffset) {
DocumentMarker newLeft = marker;
newLeft.endOffset = startOffset;
markers->insert(it - markers->begin(), newLeft);
markers.insert(it - markers.begin(), newLeft);
rects.insert(it - markers.begin(), placeholderRectForMarker());
// it now points to the newly-inserted node, but we want to skip that one
it++;
}
if (marker.endOffset > endOffset) {
DocumentMarker newRight = marker;
newRight.startOffset = endOffset;
markers->insert(it - markers->begin(), newRight);
markers.insert(it - markers.begin(), newRight);
rects.insert(it - markers.begin(), placeholderRectForMarker());
// it now points to the newly-inserted node, but we want to skip that one
it++;
}
}
if (markers->isEmpty()) {
if (markers.isEmpty()) {
ASSERT(rects.isEmpty());
m_markers.remove(node);
delete markers;
delete vectorPair;
}
// repaint the affected node
......@@ -2804,12 +2825,45 @@ void Document::removeMarkers(Node *node, unsigned startOffset, int length, Docum
Vector<DocumentMarker> Document::markersForNode(Node* node)
{
Vector<DocumentMarker>* markers = m_markers.get(node);
if (markers)
return *markers;
MarkerMapVectorPair* vectorPair = m_markers.get(node);
if (vectorPair)
return vectorPair->first;
return Vector<DocumentMarker>();
}
Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
{
Vector<IntRect> result;
// outer loop: process each node
MarkerMap::iterator end = m_markers.end();
for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
// inner loop; process each marker in this node
MarkerMapVectorPair* vectorPair = nodeIterator->second;
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<IntRect>& rects = vectorPair->second;
ASSERT(markers.size() == rects.size());
unsigned markerCount = markers.size();
for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
DocumentMarker marker = markers[markerIndex];
// skip marker that is wrong type
if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
continue;
IntRect r = rects[markerIndex];
// skip placeholder rects
if (r == placeholderRectForMarker())
continue;
result.append(r);
}
}
return result;
}
void Document::removeMarkers(Node* node)
{
MarkerMap::iterator i = m_markers.find(node);
......@@ -2831,9 +2885,12 @@ void Document::removeMarkers(DocumentMarker::MarkerType markerType)
bool nodeNeedsRepaint = false;
// inner loop: process each marker in the current node
Vector<DocumentMarker> *markers = i->second;
MarkerMapVectorPair* vectorPair = i->second;
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<IntRect>& rects = vectorPair->second;
ASSERT(markers.size() == rects.size());
Vector<DocumentMarker>::iterator markerIterator;
for (markerIterator = markers->begin(); markerIterator != markers->end();) {
for (markerIterator = markers.begin(); markerIterator != markers.end();) {
DocumentMarker marker = *markerIterator;
// skip nodes that are not of the specified type
......@@ -2843,7 +2900,8 @@ void Document::removeMarkers(DocumentMarker::MarkerType markerType)
}
// pitch the old marker
markers->remove(markerIterator - markers->begin());
markers.remove(markerIterator - markers.begin());
rects.remove(markerIterator - markers.begin());
nodeNeedsRepaint = true;
// markerIterator now points to the next node
}
......@@ -2857,8 +2915,11 @@ void Document::removeMarkers(DocumentMarker::MarkerType markerType)
}
// delete the node's list if it is now empty
if (markers->isEmpty())
if (markers.isEmpty()) {
ASSERT(rects.isEmpty());
m_markers.remove(node);
delete vectorPair;
}
}
}
......@@ -2870,10 +2931,11 @@ void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
Node* node = i->first.get();
// inner loop: process each marker in the current node
Vector<DocumentMarker> *markers = i->second;
MarkerMapVectorPair* vectorPair = i->second;
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<DocumentMarker>::iterator markerIterator;
bool nodeNeedsRepaint = false;
for (markerIterator = markers->begin(); markerIterator != markers->end(); ++markerIterator) {
for (markerIterator = markers.begin(); markerIterator != markers.end(); ++markerIterator) {
DocumentMarker marker = *markerIterator;
// skip nodes that are not of the specified type
......@@ -2892,21 +2954,50 @@ void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
}
}
void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, IntRect r)
{
Vector<DocumentMarker>* markers = m_markers.get(node);
if (!markers)
MarkerMapVectorPair* vectorPair = m_markers.get(node);
if (!vectorPair) {
ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
return;
}
Vector<DocumentMarker>& markers = vectorPair->first;
ASSERT(markers.size() == vectorPair->second.size());
unsigned markerCount = markers.size();
for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
DocumentMarker m = markers[markerIndex];
if (m == marker) {
vectorPair->second[markerIndex] = r;
return;
}
}
ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
}
void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
{
MarkerMapVectorPair* vectorPair = m_markers.get(node);
if (!vectorPair)
return;
Vector<DocumentMarker>& markers = vectorPair->first;
Vector<IntRect>& rects = vectorPair->second;
ASSERT(markers.size() == rects.size());
bool docDirty = false;
Vector<DocumentMarker>::iterator it;
for (it = markers->begin(); it != markers->end(); ++it) {
for (it = markers.begin(); it != markers.end(); ++it) {
DocumentMarker &marker = *it;
if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
assert((int)marker.startOffset + delta >= 0);
marker.startOffset += delta;
marker.endOffset += delta;
docDirty = true;
// Marker moved, so previously-computed rendered rectangle is now invalid
rects[it - markers.begin()] = placeholderRectForMarker();
}
}
......
......@@ -531,9 +531,11 @@ public:
void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
void removeMarkers(Node*);
void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
void setRenderedRectForMarker(Node*, DocumentMarker, IntRect);
void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
Vector<DocumentMarker> markersForNode(Node*);
Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
// designMode support
enum InheritedBool { off = false, on = true, inherit };
......@@ -657,7 +659,8 @@ protected:
RenderArena* m_renderArena;
typedef HashMap<RefPtr<Node>, Vector<DocumentMarker>*> MarkerMap;
typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair;
typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap;
MarkerMap m_markers;
mutable AccessibilityObjectCache* m_accCache;
......
......@@ -282,8 +282,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
if (haveMarkedText && !markedTextUsesUnderlines)
paintMarkedTextBackground(i.p, tx, ty, styleToUse, font, markedTextRange->startOffset(exception), markedTextRange->endOffset(exception));
if (object()->document()->frame()->markedTextMatchesAreHighlighted())
paintAllMarkersOfType(i.p, tx, ty, DocumentMarker::TextMatch, styleToUse, font);
paintAllMarkersOfType(i.p, tx, ty, DocumentMarker::TextMatch, styleToUse, font);
if (haveSelection)
paintSelection(i.p, tx, ty, styleToUse, font);
......@@ -577,21 +576,31 @@ void InlineTextBox::paintSpellingMarker(GraphicsContext* pt, int _tx, int _ty, D
void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, int _tx, int _ty, DocumentMarker marker, RenderStyle* style, const Font* f)
{
Color yellow = Color(255, 255, 0);
pt->save();
pt->setPen(yellow); // Don't draw text at all!
// Use same y positioning and height as for selection, so that when the selection and this highlight are on
// the same word there are no pieces sticking out.
RootInlineBox* r = root();
int y = r->selectionTop();
int h = r->selectionHeight();
pt->addClip(IntRect(_tx + m_x, _ty + y, m_width, h));
int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
TextRun run = TextRun(textObject()->string(), m_start, m_len, sPos, ePos);
TextStyle renderStyle = TextStyle(textObject()->tabWidth(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered());
IntPoint startPoint = IntPoint(m_x + _tx, y + _ty);
pt->drawHighlightForText(TextRun(textObject()->string(), m_start, m_len, sPos, ePos), IntPoint(m_x + _tx, y + _ty), h,
TextStyle(textObject()->tabWidth(), textPos(), m_toAdd, m_reversed, m_dirOverride || style->visuallyOrdered()), yellow);
pt->restore();
// Always compute and store the rect associated with this marker
IntRect markerRect = enclosingIntRect(f->selectionRectForText(run, renderStyle, startPoint, h));
object()->document()->setRenderedRectForMarker(object()->node(), marker, markerRect);
// Optionally highlight the text
if (object()->document()->frame()->markedTextMatchesAreHighlighted()) {
Color yellow = Color(255, 255, 0);
pt->save();
pt->setPen(yellow); // Don't draw text at all!
pt->addClip(IntRect(_tx + m_x, _ty + y, m_width, h));
pt->drawHighlightForText(run, startPoint, h, renderStyle, yellow);
pt->restore();
}
}
void InlineTextBox::paintAllMarkersOfType(GraphicsContext* pt, int _tx, int _ty, DocumentMarker::MarkerType markerType, RenderStyle* style, const Font* f)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment