Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 120 additions & 30 deletions Source/CFAttributedString.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,14 @@ CFAttributedStringCacheAttribute (CFDictionaryRef attribs)
cachedAttr = insert;
CFRelease (insert);
}

else
{
/* Another run now references this cached attribute set; bump its bag
* count so it survives until every referencing run is uncached.
*/
CFBagAddValue (_kCFAttributedStringCache, cachedAttr);
}

GSMutexUnlock (&_kCFAttributedStringCacheLock);

return cachedAttr;
Expand Down Expand Up @@ -284,8 +291,8 @@ CFAttributedStringGetTypeID (void)
return _kCFAttributedStringTypeID;
}

#define CFATTRIBUTESTRING_SIZE sizeof(CFRuntimeClass) \
- sizeof(struct __CFAttributedString)
#define CFATTRIBUTESTRING_SIZE (sizeof(struct __CFAttributedString) \
- sizeof(CFRuntimeBase))

static CFAttributedStringRef
CFAttributedStringCreateInlined (CFAllocatorRef alloc, CFStringRef str,
Expand Down Expand Up @@ -423,15 +430,95 @@ CFAttributedStringGetAttributeAndLongestEffectiveRange (
CFAttributedStringRef str, CFIndex loc, CFStringRef attrName,
CFRange inRange, CFRange *longestEffRange)
{
return NULL; /* FIXME */
CFRange r;
CFTypeRef value;
CFIndex start;
CFIndex end;
CFIndex inEnd;

value = CFAttributedStringGetAttribute (str, loc, attrName, &r);
start = r.location;
end = r.location + r.length;
inEnd = inRange.location + inRange.length;

while (start > inRange.location)
{
CFRange pr;
CFTypeRef pv = CFAttributedStringGetAttribute (str, start - 1, attrName,
&pr);
if ((pv == NULL) != (value == NULL)
|| (pv != NULL && !CFEqual (pv, value)))
break;
start = pr.location;
}
while (end < inEnd)
{
CFRange nr;
CFTypeRef nv = CFAttributedStringGetAttribute (str, end, attrName, &nr);
if ((nv == NULL) != (value == NULL)
|| (nv != NULL && !CFEqual (nv, value)))
break;
end = nr.location + nr.length;
}

if (start < inRange.location)
start = inRange.location;
if (end > inEnd)
end = inEnd;
if (longestEffRange)
{
longestEffRange->location = start;
longestEffRange->length = end - start;
}

return value;
}

CFDictionaryRef
CFAttributedStringGetAttributesAndLongestEffectiveRange (
CFAttributedStringRef str, CFIndex loc, CFRange inRange,
CFRange *longestEffRange)
{
return NULL; /* FIXME */
CFRange r;
CFDictionaryRef attribs;
CFIndex start;
CFIndex end;
CFIndex inEnd;

attribs = CFAttributedStringGetAttributes (str, loc, &r);
start = r.location;
end = r.location + r.length;
inEnd = inRange.location + inRange.length;

while (start > inRange.location)
{
CFRange pr;
CFDictionaryRef pa = CFAttributedStringGetAttributes (str, start - 1,
&pr);
if (!CFEqual (pa, attribs))
break;
start = pr.location;
}
while (end < inEnd)
{
CFRange nr;
CFDictionaryRef na = CFAttributedStringGetAttributes (str, end, &nr);
if (!CFEqual (na, attribs))
break;
end = nr.location + nr.length;
}

if (start < inRange.location)
start = inRange.location;
if (end > inEnd)
end = inEnd;
if (longestEffRange)
{
longestEffRange->location = start;
longestEffRange->length = end - start;
}

return attribs;
}


Expand All @@ -451,12 +538,13 @@ InsertAttributesAtIndex (CFMutableAttributedStringRef str, CFIndex idx,
if (working->_attribCount == working->_attribCap)
{
/* Grow */
working->_attribCap <<= 1;
working->_attribs = CFAllocatorReallocate (alloc,
working->_attribs,
(working->_attribCap << 1),
sizeof(Attr) * working->_attribCap,
0);
}

/* Move things to the right */
stop = &working->_attribs[idx];
cur = &working->_attribs[working->_attribCount];
Expand Down Expand Up @@ -528,18 +616,19 @@ RemoveAttributesAtIndex (CFMutableAttributedStringRef str, CFRange range)

cur = &working->_attribs[range.location];
next = cur + range.length;
stop = cur + (working->_attribCount - (range.location + range.length) - 1);
stop = cur + (working->_attribCount - (range.location + range.length));
while (cur < stop)
*cur++ = *next++;
working->_attribCount -= range.length;

if (working->_attribCount < (working->_attribCap >> 2)
&& working->_attribCount > 9)
{
/* Shrink */
working->_attribCap >>= 1;
working->_attribs = CFAllocatorReallocate (alloc,
working->_attribs,
(working->_attribCap >> 1),
sizeof(Attr) * working->_attribCap,
0);
}
}
Expand All @@ -556,35 +645,35 @@ CFAttributedStringCoalesce (CFMutableAttributedStringRef str, CFRange range)
{
CFIndex cur;
CFIndex end;
Attr *array;

array = working->_attribs;
if (range.location > 0)
{
if (array[range.location - 1].attrib == array[range.location].attrib)
{
RemoveAttributesAtIndex (str, CFRangeMake (range.location, 1));
range.length -= 1;
}
}

cur = range.location;
end = range.location + range.length;

Attr *array = working->_attribs;

/* Run 0 has no predecessor to merge into, so start at 1. Also fold in
* the run that immediately follows the affected range, since removing
* attributes can make it equal to its new predecessor.
*/
cur = range.location < 1 ? 1 : range.location;
end = range.location + range.length + 1;
if (end > working->_attribCount)
end = working->_attribCount;

while (cur < end)
{
if (array[cur - 1].attrib == array[cur].attrib)
if (array[cur].attrib == array[cur - 1].attrib)
{
/* This run repeats its predecessor: drop it (the predecessor's
* range absorbs it) and re-check the run now shifted into cur.
*/
RemoveAttributesAtIndex (str, CFRangeMake (cur, 1));
end -= 1;
}
cur++;
else
cur += 1;
}
}
}

#define CFMUTABLEATTRIBUTESTRING_SIZE sizeof(CFRuntimeClass) \
- sizeof(struct __CFMutableAttributedString)
#define CFMUTABLEATTRIBUTESTRING_SIZE (sizeof(struct __CFMutableAttributedString) \
- sizeof(CFRuntimeBase))

CFMutableAttributedStringRef
CFAttributedStringCreateMutable (CFAllocatorRef alloc, CFIndex maxLength)
Expand All @@ -602,7 +691,8 @@ CFAttributedStringCreateMutable (CFAllocatorRef alloc, CFIndex maxLength)
new->_attribCount = 1;
new->_attribs[0].index = 0;
new->_attribs[0].attrib = CFAttributedStringGetBlankAttribute ();

new->_isEditing = 0;

CFAttributedStringSetMutable ((CFAttributedStringRef)new);
}

Expand Down
2 changes: 1 addition & 1 deletion Source/CFBag.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ CFBagCreateMutableCopy (CFAllocatorRef allocator, CFIndex capacity,
void
CFBagAddValue (CFMutableBagRef bag, const void *value)
{
GSHashTableAddValue ((GSHashTableRef)bag, value, value);
GSHashTableAddValueCounted ((GSHashTableRef)bag, value, value);
}

void
Expand Down
2 changes: 1 addition & 1 deletion Source/GSFunctions.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ GSBSearch (const void *array, const void *key, CFRange range, CFIndex size,
r = comp (key, cur, ctxt);
if (r == kCFCompareLessThan)
{
max = mid - 1;
max = mid;
}
else if (r == kCFCompareGreaterThan)
{
Expand Down
26 changes: 26 additions & 0 deletions Source/GSHashTable.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,32 @@ GSHashTableAddValue (GSHashTableRef table, const void *key, const void *value)
}
}

void
GSHashTableAddValueCounted (GSHashTableRef table, const void *key,
const void *value)
{
GSHashTableBucket *bucket;

GSHashTableGrowIfNeeded (table);

bucket = GSHashTableFindBucket (table, key, _kGSHashTableRetrieve);
if (!bucket)
bucket = GSHashTableFindBucket (table, key, _kGSHashTableInsert);

if (bucket->count <= 0)
{
GSHashTableAddKeyValuePair (table, bucket, key, value);
table->_count += 1;
}
else
{
/* Increment the multiplicity so a bag counts repeated additions;
* GSHashTableRemoveValue decrements it symmetrically.
*/
bucket->count += 1;
}
}

void
GSHashTableReplaceValue (GSHashTableRef table, const void *key,
const void *value)
Expand Down
4 changes: 4 additions & 0 deletions Source/GSHashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ GSHashTableCreateMutableCopy (CFAllocatorRef alloc, GSHashTableRef table,
GS_PRIVATE void
GSHashTableAddValue (GSHashTableRef table, const void *key, const void *value);

GS_PRIVATE void
GSHashTableAddValueCounted (GSHashTableRef table, const void *key,
const void *value);

GS_PRIVATE void
GSHashTableReplaceValue (GSHashTableRef table, const void *key,
const void *value);
Expand Down
52 changes: 52 additions & 0 deletions Tests/CFAttributedString/longest_range.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "CoreFoundation/CFAttributedString.h"
#include "CoreFoundation/CFString.h"
#include "CoreFoundation/CFDictionary.h"

#include "../CFTesting.h"

int
main (void)
{
CFRange lr;
CFTypeRef v;
CFDictionaryRef d;
CFMutableAttributedStringRef m;

m = CFAttributedStringCreateMutable (NULL, 0);
CFAttributedStringReplaceString (m, CFRangeMake (0, 0), CFSTR ("Hello World"));
/* (0,5) = {color, shared}, (5,11) = {weight, shared}. */
CFAttributedStringSetAttribute (m, CFRangeMake (0, 5), CFSTR ("color"),
CFSTR ("red"));
CFAttributedStringSetAttribute (m, CFRangeMake (0, 11), CFSTR ("shared"),
CFSTR ("x"));
CFAttributedStringSetAttribute (m, CFRangeMake (5, 6), CFSTR ("weight"),
CFSTR ("bold"));

v = CFAttributedStringGetAttributeAndLongestEffectiveRange (
m, 2, CFSTR ("shared"), CFRangeMake (0, 11), &lr);
PASS_CFEQ(v, CFSTR ("x"), "The longest-range shared value is returned.");
PASS_CF(lr.location == 0 && lr.length == 11,
"shared has the same value across both runs.");

v = CFAttributedStringGetAttributeAndLongestEffectiveRange (
m, 2, CFSTR ("color"), CFRangeMake (0, 11), &lr);
PASS_CFEQ(v, CFSTR ("red"), "The longest-range color value is returned.");
PASS_CF(lr.location == 0 && lr.length == 5,
"color has the same value only over (0,5).");

d = CFAttributedStringGetAttributesAndLongestEffectiveRange (
m, 8, CFRangeMake (0, 11), &lr);
PASS_CF(d != NULL && CFDictionaryGetCount (d) == 2,
"The longest-range attributes at 8 are the second run's two.");
PASS_CF(lr.location == 5 && lr.length == 6,
"The full attribute set stays equal only over (5,6).");

v = CFAttributedStringGetAttributeAndLongestEffectiveRange (
m, 2, CFSTR ("shared"), CFRangeMake (0, 3), &lr);
PASS_CF(lr.location == 0 && lr.length == 3,
"The longest range is clamped to the search range.");

CFRelease (m);

return 0;
}
Loading
Loading