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