Revision: 4847
          http://skim-app.svn.sourceforge.net/skim-app/?rev=4847&view=rev
Author:   hofman
Date:     2008-10-22 12:42:40 +0000 (Wed, 22 Oct 2008)

Log Message:
-----------
Improved and more consistent determination of selection ranges for recursive 
specifiers

Modified Paths:
--------------
    trunk/PDFSelection_SKExtensions.m

Modified: trunk/PDFSelection_SKExtensions.m
===================================================================
--- trunk/PDFSelection_SKExtensions.m   2008-10-22 10:06:47 UTC (rev 4846)
+++ trunk/PDFSelection_SKExtensions.m   2008-10-22 12:42:40 UTC (rev 4847)
@@ -151,127 +151,127 @@
     return range;
 }
 
-static NSArray *characterRangesForSpecifier(NSScriptObjectSpecifier *spec, 
NSScriptObjectSpecifier **containerSpec) {
-    if ([spec isKindOfClass:[NSScriptObjectSpecifier class]] == NO)
+static NSArray *characterRangesForSpecifier(NSScriptObjectSpecifier 
*specifier, NSScriptObjectSpecifier **containerSpecifier, NSTextStorage 
**containerTextStorage) {
+    if ([specifier isKindOfClass:[NSScriptObjectSpecifier class]] == NO)
         return nil;
     
     // we should get ranges of characters, words, or parapgraphs of the 
richText of a page
-    NSString *key = [spec key];
+    NSString *key = [specifier key];
     NSSet *textKeys = [NSSet setWithObjects:@"characters", @"words", 
@"paragraphs", @"attributeRuns", nil];
     if ([textKeys containsObject:key] == NO)
         return nil;
     
-    // get the richText specifier
-    NSScriptObjectSpecifier *textSpec = [spec containerSpecifier];
-    NSTextStorage *textStorage = [textSpec objectsByEvaluatingSpecifier];
-    if ([textStorage isKindOfClass:[NSArray class]])
-        textStorage = [(NSArray *)textStorage count] == 1 ? [(NSArray 
*)textStorage objectAtIndex:0] : nil;
-    if ([textStorage isKindOfClass:[NSTextStorage class]] == NO)
-        return nil;
-    
-    unsigned int containerOffset = 0;
-    if ([textKeys containsObject:[textSpec key]]) {
-        NSArray *textRanges = characterRangesForSpecifier(textSpec, 
containerSpec);
+    // get the richText specifier and textStorage
+    NSScriptObjectSpecifier *containerSpec = [specifier containerSpecifier];
+    NSArray *textRanges = nil;
+    NSTextStorage *containerText = nil;
+    if ([textKeys containsObject:[containerSpec key]]) {
+        textRanges = characterRangesForSpecifier(containerSpec, 
containerSpecifier, &containerText);
         if ([textRanges count] == 0)
             return nil;
-        containerOffset = [[textRanges objectAtIndex:0] rangeValue].location;
     } else {
-        *containerSpec = textSpec;
+        containerText = [containerSpec objectsByEvaluatingSpecifier];
+        if ([containerText isKindOfClass:[NSArray class]])
+            containerText = [(NSArray *)containerText count] == 1 ? [(NSArray 
*)containerText objectAtIndex:0] : nil;
+        if ([containerText isKindOfClass:[NSTextStorage class]] == NO)
+            return nil;
+        textRanges = [NSArray arrayWithObject:[NSValue 
valueWithRange:NSMakeRange(0, [containerText length])]];
+        *containerSpecifier = containerSpec;
     }
+    if (containerTextStorage)
+        *containerTextStorage = containerText;
     
-    // now get the ranges, which can be any kind of specifier
-    int startIndex, endIndex, i, count, *indices;
-    NSRange *ranges = NULL;
-    int numRanges = 0;
+    NSEnumerator *rangeEnum = [textRanges objectEnumerator];
+    NSValue *value;
+    NSMutableArray *rangeValues = [NSMutableArray array];
     
-    if ([spec isKindOfClass:[NSPropertySpecifier class]]) {
-        // this should be the full range of characters, words, or paragraphs
-        numRanges = 1;
-        ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, sizeof(NSRange));
-        ranges[0] = NSMakeRange(0, [[textStorage valueForKey:key] count]);
-    } else if ([spec isKindOfClass:[NSRangeSpecifier class]]) {
-        // somehow getting the indices as for the general case sometimes leads 
to an exception for NSRangeSpecifier, so we get the indices of the 
start/endSpecifiers
-        NSScriptObjectSpecifier *startSpec = [(NSRangeSpecifier *)spec 
startSpecifier];
-        NSScriptObjectSpecifier *endSpec = [(NSRangeSpecifier *)spec 
endSpecifier];
+    while (value = [rangeEnum nextObject]) {
+        NSRange textRange = [value rangeValue];
+        NSTextStorage *textStorage = [[NSTextStorage alloc] 
initWithAttributedString:[containerText 
attributedSubstringFromRange:textRange]];
         
-        if (startSpec == nil && endSpec == nil)
-            return nil;
+        // now get the ranges, which can be any kind of specifier
+        int startIndex, endIndex, i, count, *indices;
+        NSRange *ranges = NULL;
+        int numRanges = 0;
         
-        if (startSpec) {
-            indices = [startSpec 
indicesOfObjectsByEvaluatingWithContainer:textStorage count:&count];
-            if (count <= 0)
-                return nil;
-            startIndex = indices[0];
+        if ([specifier isKindOfClass:[NSPropertySpecifier class]]) {
+            // this should be the full range of characters, words, or 
paragraphs
+            numRanges = 1;
+            ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, 
sizeof(NSRange));
+            ranges[0] = NSMakeRange(0, [[textStorage valueForKey:key] count]);
+        } else if ([specifier isKindOfClass:[NSRangeSpecifier class]]) {
+            // somehow getting the indices as for the general case sometimes 
leads to an exception for NSRangeSpecifier, so we get the indices of the 
start/endSpecifiers
+            NSScriptObjectSpecifier *startSpec = [(NSRangeSpecifier 
*)specifier startSpecifier];
+            NSScriptObjectSpecifier *endSpec = [(NSRangeSpecifier *)specifier 
endSpecifier];
+            
+            if (startSpec || endSpec) {
+                if (startSpec) {
+                    indices = [startSpec 
indicesOfObjectsByEvaluatingWithContainer:textStorage count:&count];
+                    startIndex = count ? indices[0] : -1;
+                } else {
+                    startIndex = 0;
+                }
+                if (endSpec) {
+                    indices = [endSpec 
indicesOfObjectsByEvaluatingWithContainer:textStorage count:&count];
+                    endIndex = count ? indices[count - 1] : -1;
+                } else {
+                    endIndex = [[textStorage valueForKey:key] count];
+                }
+                if (startIndex >= 0 && endIndex >= 0) {
+                    numRanges = 1;
+                    ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, 
sizeof(NSRange));
+                    ranges[0] = NSMakeRange(MIN(startIndex, endIndex), 
MAX(startIndex, endIndex) + 1 - MIN(startIndex, endIndex));
+                }
+            }
         } else {
-            startIndex = 0;
+            // this handles other objectSpecifiers (index, middel, random, 
relative, whose). It can contain several ranges, e.g. for aan NSWhoseSpecifier
+            indices = [specifier 
indicesOfObjectsByEvaluatingWithContainer:textStorage count:&count];
+            for (i = 0; i < count; i++) {
+                unsigned int idx = indices[i];
+                if (numRanges == 0 || idx > NSMaxRange(ranges[numRanges - 1])) 
{
+                    numRanges++;
+                    ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, 
numRanges * sizeof(NSRange));
+                    ranges[numRanges - 1] = NSMakeRange(idx, 1);
+                } else {
+                    ++(ranges[numRanges - 1].length);
+                }
+            }
         }
         
-        if (endSpec) {
-            indices = [endSpec 
indicesOfObjectsByEvaluatingWithContainer:textStorage count:&count];
-            if (count <= 0)
-                return nil;
-            endIndex = indices[count - 1];
+        if (numRanges == 0) {
+        } else if ([key isEqualToString:@"characters"]) {
+            for (i = 0; i < numRanges; i++) {
+                NSRange range = ranges[i];
+                range.location += textRange.location;
+                range = NSIntersectionRange(range, textRange);
+                if (range.length)
+                    [rangeValues addObject:[NSValue valueWithRange:range]];
+            }
         } else {
-            endIndex = [[textStorage valueForKey:key] count];
-        }
-        
-        numRanges = 1;
-        ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, sizeof(NSRange));
-        ranges[0] = NSMakeRange(MIN(startIndex, endIndex), MAX(startIndex, 
endIndex) + 1 - MIN(startIndex, endIndex));
-    } else {
-        // this handles other objectSpecifiers (index, middel, random, 
relative, whose). It can contain several ranges, e.g. for aan NSWhoseSpecifier
-        indices = [spec indicesOfObjectsByEvaluatingWithContainer:textStorage 
count:&count];
-        if (count <= 0)
-            return nil;
-        
-        for (i = 0; i < count; i++) {
-            unsigned int idx = indices[i];
-            if (numRanges == 0 || idx > NSMaxRange(ranges[numRanges - 1])) {
-                numRanges++;
-                ranges = NSZoneRealloc(NSDefaultMallocZone(), ranges, 
numRanges * sizeof(NSRange));
-                ranges[numRanges - 1] = NSMakeRange(idx, 1);
-            } else {
-                ++(ranges[numRanges - 1].length);
-            }
-        }
-    }
-    
-    if ([key isEqualToString:@"characters"] == NO) {
-        // translate from subtext ranges to character ranges
-        for (i = 0; i < numRanges; i++) {
-            startIndex = ranges[i].location;
-            endIndex = NSMaxRange(ranges[i]) - 1;
+            // translate from subtext ranges to character ranges
             NSString *string = [textStorage string];
             NSArray *substrings = [[textStorage valueForKey:key] 
valueForKey:@"string"];
-            NSRange range = rangeOfSubstringOfStringAtIndex(string, 
substrings, startIndex);
-            if (range.location == NSNotFound) {
-                ranges[i] = NSMakeRange(NSNotFound, 0);
-                continue;
-            }
-            startIndex = range.location;
-            if (ranges[i].length > 1) {
-                range = rangeOfSubstringOfStringAtIndex(string, substrings, 
endIndex);
-                if (range.location == NSNotFound) {
-                    ranges[i] = NSMakeRange(NSNotFound, 0);
+            for (i = 0; i < numRanges; i++) {
+                startIndex = MIN(ranges[i].location, [substrings count]);
+                endIndex = MIN(NSMaxRange(ranges[i]) - 1, [substrings count]);
+                if (endIndex == startIndex) endIndex = -1;
+                NSRange range = rangeOfSubstringOfStringAtIndex(string, 
substrings, startIndex);
+                if (range.location == NSNotFound)
                     continue;
+                startIndex = range.location;
+                if (endIndex >= 0) {
+                    range = rangeOfSubstringOfStringAtIndex(string, 
substrings, endIndex);
+                    if (range.location == NSNotFound)
+                        continue;
                 }
+                endIndex = NSMaxRange(range) - 1;
+                [rangeValues addObject:[NSValue 
valueWithRange:NSMakeRange(textRange.location + startIndex, endIndex + 1 - 
startIndex)]];
             }
-            endIndex = NSMaxRange(range) - 1;
-            ranges[i] = NSMakeRange(startIndex, endIndex + 1 - startIndex);
         }
+        
+        if (ranges) NSZoneFree(NSDefaultMallocZone(), ranges);
+        [textStorage release];
     }
-    
-    NSMutableArray *rangeValues = [NSMutableArray array];
-    
-    for (i = 0; i < numRanges; i++) {
-        NSRange range = ranges[i];
-        if (range.length) {
-            range.location += containerOffset;
-            [rangeValues addObject:[NSValue valueWithRange:range]];
-        }
-    }
-    if (ranges) NSZoneFree(NSDefaultMallocZone(), ranges);
-    
     return rangeValues;
 }
 
@@ -320,7 +320,7 @@
             ranges = [NSArray arrayWithObjects:[NSValue 
valueWithRange:NSMakeRange(0, [textStorage length])], nil];
             textSpec = spec;
         } else if ([textKeys containsObject:key]) {
-            ranges = characterRangesForSpecifier(spec, &textSpec);
+            ranges = characterRangesForSpecifier(spec, &textSpec, NULL);
             if ([textSpec isKindOfClass:[NSScriptObjectSpecifier class]] == NO 
|| [[textSpec key] isEqualToString:@"richText"] == NO)
                 continue;
         } else


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to