Permalink
Browse files

Merge branch 'bgdrawing'

  • Loading branch information...
2 parents 115f6cc + c3b96c0 commit eae6fc0eb4b2b71c40db43a62647e1a9159ec5fc @wiml wiml committed Mar 14, 2011
@@ -1,25 +1,25 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf290
-{\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 GillSans;}
-{\colortbl;\red255\green255\blue255;\red5\green0\blue137;}
-\margl1440\margr1440\vieww9000\viewh8400\viewkind0
-\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
-
-\f0\fs24 \cf0 Hello CoreText!\
+{\rtf1\ansi\ansicpg1252
+{\fonttbl\f0\fnil\fcharset0 Helvetica;\f1\fnil\fcharset0 Helvetica-Oblique;\f2\fnil\fcharset0 Helvetica-Bold;\f3\fnil\fcharset0 GillSans;}
+{\colortbl;\red5\green0\blue137;\red255\green255\blue255;}
+\f0\fs24 \cf0 \ri8640
+Hello CoreText!\
\
Use the context menu on some text to inspect and alter styles.\
\
-
\i italic\
\i0\b bold\
-\b0 \cf2 color\
+\b0 \cf1 foreground color\
-\fs28 \cf0 bigger\
+\cf2 \cb1 background color\
-\f1\fs24 Gill Sans\
+\fs28 \cf0 \cb0 bigger \fs38 and bigger\
+
+\f3 \fs24 Gill Sans\
\f0 \ul underlined\
+
\ulnone \
\
-}
+}
@@ -78,8 +78,9 @@
unsigned showSelectionThumbs: 1; // Effectively disables range selection
unsigned showsInspector: 1; // Whether the inspector is offered
- //
- unsigned immutableContentHasAttributeTransforms: 1;
+ // Information about our content
+ unsigned immutableContentHasAttributeTransforms: 1; // False if our -attributedText isn't a simple subrange of immutableContent
+ unsigned mayHaveBackgroundRanges: 1; // True unless we know we don't have any ... .
} flags;
// Range selection adjustment and display
@@ -225,6 +225,26 @@ static inline CGFloat dist_sqr(CGPoint a, CGPoint b)
return dx*dx + dy*dy;
}
+/* Aligns an extent (one dimension of a rectangle) so that its edges lie on half-integer coordinates, under the 1-dimensional affine transform given by translate and scale. This attempts to keep the rectangle's size roughly the same, unlike CGRectIntegral() (but like -[NSView centerScanRect:]). */
+static void alignExtentToPixelCenters(CGFloat translate, CGFloat scale, CGFloat *origin, CGFloat *size)
+{
+ CGFloat xsize = *size * scale;
+ CGFloat xorigin = ( *origin * scale ) + translate;
+ CGFloat rxsize = round(xsize);
+ CGFloat adjustment = xsize - rxsize;
+ CGFloat rxorigin = xorigin;
+
+ if (fabs(adjustment) > 1e-3) {
+ *size = ( rxsize / scale );
+ rxorigin += adjustment * 0.5;
+ }
+
+ rxorigin = floor(rxorigin) + 0.5;
+ if (fabs(rxorigin - xorigin) > 1e-3) {
+ *origin = ( rxorigin - translate ) / scale;
+ }
+}
+
/*
Searches for the CTLine containing a given string index (queryIndex), confining the search to the range [l,h).
The line's index is returned and a line ref is stored in *foundLine.
@@ -3312,6 +3332,7 @@ - (void)_inspectTap:(UILongPressGestureRecognizer *)r;
struct rectpathwalkerLineBottom {
CGFloat descender, left, right;
} currentLine, previousLine;
+ CGAffineTransform *centerScanUnderTransform;
BOOL includeInterline; // Whether to extend lines vertically to fill gaps
};
@@ -3326,6 +3347,8 @@ static void getMargins(OUIEditableFrame *self, struct rectpathwalker *r)
r->currentLine = (struct rectpathwalkerLineBottom){ NAN, NAN, NAN };
r->previousLine = (struct rectpathwalkerLineBottom){ NAN, NAN, NAN };
+
+ r->centerScanUnderTransform = NULL;
}
static BOOL addRectsToPath(CGPoint p, CGFloat width, CGFloat trailingWS, CGFloat ascent, CGFloat descent, unsigned flags, void *ctxt)
@@ -3375,6 +3398,11 @@ layoutOrigin is the location (in our rendering coordinates) of the origin of the
highlightRect.size.width = width;
}
+ if (r->centerScanUnderTransform) {
+ alignExtentToPixelCenters(r->centerScanUnderTransform->tx, r->centerScanUnderTransform->a, &highlightRect.origin.x, &highlightRect.size.width);
+ alignExtentToPixelCenters(r->centerScanUnderTransform->ty, r->centerScanUnderTransform->d, &highlightRect.origin.y, &highlightRect.size.height);
+ }
+
if (r->includeInterline) {
if (flags & rectwalker_FirstRectInLine) {
/* If we're the first rectangle in the line, set up our record of this line's highlights' extent, and possibly copy the previously calculated record to previousLine. */
@@ -3420,7 +3448,42 @@ - (void)_drawDecorationsBelowText:(CGContextRef)ctx
if (!drawnFrame || flags.textNeedsUpdate)
return;
- /* TODO: Draw text background (iterate over runs) */
+ /* Draw any text background runs */
+ if (flags.mayHaveBackgroundRanges) {
+ BOOL sawAnything = NO;
+
+ NSUInteger cursor = 0;
+ NSUInteger textLength = [immutableContent length];
+ while (cursor < textLength) {
+ NSRange span = { 0, 0 };
+ CGColorRef bgColor = (CGColorRef)[immutableContent attribute:OABackgroundColorAttributeName
+ atIndex:cursor
+ longestEffectiveRange:&span
+ inRange:(NSRange){cursor, textLength-cursor}];
+ if (!span.length)
+ break;
+
+ if (bgColor && CGColorGetAlpha(bgColor) > 0) {
+ sawAnything = YES;
+
+ struct rectpathwalker ctxt;
+ ctxt.ctxt = ctx;
+ ctxt.includeInterline = YES;
+ getMargins(self, &ctxt);
+
+ CGContextSetFillColorWithColor(ctx, bgColor);
+ CGContextBeginPath(ctx);
+ rectanglesInRange(drawnFrame, span, NO, addRectsToPath, &ctxt);
+ CGContextFillPath(ctx);
+ }
+
+ cursor = span.location + span.length;
+ }
+
+ if (!sawAnything)
+ flags.mayHaveBackgroundRanges = 0;
+ }
+
/* Draw the selection highlight for range selections. */
if (selection && ![selection isEmpty]) {
@@ -3471,12 +3534,15 @@ - (void)_drawDecorationsBelowText:(CGContextRef)ctx
/* We have some decorations that are drawn over the text instead of under it */
- (void)_drawDecorationsAboveText:(CGContextRef)ctx
{
+ CGAffineTransform currentCTM = CGContextGetCTM(ctx);
+
/* Draw the marked-text indication's border, if any */
if (markedRange.length && _markedRangeBorderColor) {
struct rectpathwalker ctxt;
ctxt.ctxt = ctx;
ctxt.includeInterline = NO;
getMargins(self, &ctxt);
+ ctxt.centerScanUnderTransform = &currentCTM;
CGFloat strokewidth = _markedRangeBorderThickness;
CGContextBeginPath(ctx);
@@ -3495,7 +3561,7 @@ - (void)_drawDecorationsAboveText:(CGContextRef)ctx
if (selection && [selection isEmpty]) {
// If we're being drawn zoomed, we might not need as much enlargement of the caret in order for it to be visible
CGFloat nominalScale = self.scale;
- double actualScale = sqrt(fabs(OQAffineTransformGetDilation(CGContextGetCTM(ctx))));
+ double actualScale = sqrt(fabs(OQAffineTransformGetDilation(currentCTM)));
CGRect caretRect = [self _caretRectForPosition:(OUEFTextPosition *)(selection.start) affinity:1 bloomScale:MAX(nominalScale, actualScale)];
@@ -3571,6 +3637,7 @@ - (void)_updateLayout:(BOOL)computeDrawnFrame
immutableContent = [_content copy];
flags.immutableContentHasAttributeTransforms = NO;
}
+ flags.mayHaveBackgroundRanges = 1;
framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)immutableContent);
@@ -15,6 +15,7 @@
#import <OmniFoundation/NSNumber-OFExtensions-CGTypes.h>
#import <OmniFoundation/OFStringScanner.h>
#import <OmniAppKit/OAFontDescriptor.h>
+#import <OmniAppKit/OATextAttributes.h>
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#import <CoreText/CTParagraphStyle.h>
@@ -83,6 +84,7 @@ @interface OUIRTFReaderState : OFObject <NSCopying>
NSMutableString *_alternateDestination;
CFStringEncoding _stringEncoding;
id _foregroundColor;
+ id _backgroundColor;
CGFloat _fontSize;
int _fontNumber;
int _fontCharacterSet;
@@ -107,6 +109,7 @@ @interface OUIRTFReaderState : OFObject <NSCopying>
@property (nonatomic, readwrite, retain) NSMutableString *alternateDestination;
@property (nonatomic, retain) id foregroundColor;
+@property (nonatomic, retain) id backgroundColor;
@property (nonatomic) CGFloat fontSize;
@property (nonatomic) int fontNumber;
@property (nonatomic) BOOL bold;
@@ -438,6 +441,7 @@ - (void)_addColorTableEntry;
- (void)_actionReadColorTable;
{
[self _actionSkipDestination]; // Don't let any text from the color table slip into the output stream
+ [self _resetCurrentColorTableColor];
[self _parseRTFGroupWithSemicolonAction:[[[OUIRTFReaderSelectorAction alloc] initWithSelector:@selector(_addColorTableEntry)] autorelease]];
}
@@ -525,10 +529,11 @@ - (CFStringEncoding)_fontEncodingAtIndex:(int)fontTableIndex;
- (void)_actionBackgroundColor:(int)colorTableIndex;
{
-#ifdef DEBUG_RTF_READER
CGColorRef color = [self _colorAtIndex:colorTableIndex];
- NSLog(@"Ignoring background color: %@ (%@)", (id)color, [(id)color class]);
+#ifdef DEBUG_RTF_READER
+ NSLog(@"Setting background color: %@ (%@)", (id)color, [(id)color class]);
#endif
+ _currentState.backgroundColor = (id)color;
}
- (void)_actionForegroundColor:(int)colorTableIndex;
@@ -570,7 +575,8 @@ - (void)_actionFontNumber:(int)value;
_currentState.fontNumber = value;
_currentState->_stringEncoding = [self _fontEncodingAtIndex:value];
#ifdef DEBUG_RTF_READER
- NSLog(@"Changed font number to %d (string encoding %d=[%@])", value, _currentState->_stringEncoding, CFStringGetNameOfEncoding(_currentState->_stringEncoding));
+ CFStringRef encodingName = CFStringGetNameOfEncoding(_currentState->_stringEncoding);
+ NSLog(@"Changed font number to %d (string encoding %@=[%@])", value, (NSString *)encodingName, CFStringGetNameOfEncoding(_currentState->_stringEncoding));
#endif
}
@@ -858,6 +864,7 @@ - (id)copyWithZone:(NSZone *)zone;
OUIRTFReaderState *copy = (OUIRTFReaderState *)OFCopyObject(self, 0, zone);
[copy->_alternateDestination retain];
[copy->_foregroundColor retain];
+ [copy->_backgroundColor retain];
copy->_cachedStringAttributes = nil;
return copy;
}
@@ -866,6 +873,7 @@ - (void)dealloc;
{
[_alternateDestination release];
[_foregroundColor release];
+ [_backgroundColor release];
[_cachedStringAttributes release];
[super dealloc];
}
@@ -893,7 +901,23 @@ - (void)setForegroundColor:(id)newColor;
[_foregroundColor release];
_foregroundColor = [newColor retain];
+
+ [self _resetCache];
+}
+- (id)backgroundColor;
+{
+ return _backgroundColor;
+}
+
+- (void)setBackgroundColor:(id)newColor;
+{
+ if (_backgroundColor == newColor)
+ return;
+
+ [_backgroundColor release];
+ _backgroundColor = [newColor retain];
+
[self _resetCache];
}
@@ -1014,8 +1038,10 @@ - (NSMutableDictionary *)stringAttributesForReader:(OUIRTFReader *)reader;
_cachedStringAttributes = [[NSMutableDictionary alloc] init];
if (_foregroundColor != NULL)
[_cachedStringAttributes setObject:_foregroundColor forKey:(NSString *)kCTForegroundColorAttributeName];
+ if (_backgroundColor != NULL)
+ [_cachedStringAttributes setObject:_backgroundColor forKey:OABackgroundColorAttributeName];
#ifdef DEBUG_RTF_READER
- NSLog(@"-stringAttributes: foregroundColor=%@", [OUIRTFReader debugStringForColor:_foregroundColor]);
+ NSLog(@"-stringAttributes: foregroundColor=%@ backgroundColor=%@", [OUIRTFReader debugStringForColor:_foregroundColor], [OUIRTFReader debugStringForColor:_backgroundColor]);
#endif
if ((_underline & 0xFF) != 0)
[_cachedStringAttributes setUnsignedIntValue:_underline forKey:(NSString *)kCTUnderlineStyleAttributeName];
@@ -29,7 +29,8 @@
} flags;
int fontSize;
int fontIndex;
- int colorIndex;
+ int foregroundColorIndex;
+ int backgroundColorIndex;
unsigned int underline;
OAFontDescriptor *fontDescriptor;
int alignment;
@@ -9,8 +9,10 @@
#import <OmniFoundation/OFDataBuffer.h>
#import <OmniFoundation/OFStringScanner.h>
-#import <OmniAppKit/OAFontDescriptor.h>
#import <OmniFoundation/NSDictionary-OFExtensions.h>
+#import <OmniFoundation/NSAttributedString-OFExtensions.h>
+#import <OmniAppKit/OAFontDescriptor.h>
+#import <OmniAppKit/OATextAttributes.h>
#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
#import <CoreText/CTParagraphStyle.h>
@@ -104,7 +106,8 @@ - (id)init;
_state.fontSize = -1;
_state.fontIndex = -1;
- _state.colorIndex = -1;
+ _state.foregroundColorIndex = -1;
+ _state.backgroundColorIndex = 0;
_state.underline = kCTUnderlineStyleNone;
return self;
}
@@ -239,14 +242,27 @@ - (void)_writeColorAttributes:(NSDictionary *)newAttributes;
[colorTableEntry release];
OBASSERT(newColorIndexValue != nil);
int newColorIndex = [newColorIndexValue intValue];
-
- if (newColorIndex == _state.colorIndex)
- return;
-
- OFDataBufferAppendCString(_dataBuffer, "\\cf");
- OFDataBufferAppendInteger(_dataBuffer, newColorIndex);
- OFDataBufferAppendByte(_dataBuffer, ' ');
- _state.colorIndex = newColorIndex;
+
+ if (newColorIndex != _state.foregroundColorIndex) {
+ OFDataBufferAppendCString(_dataBuffer, "\\cf");
+ OFDataBufferAppendInteger(_dataBuffer, newColorIndex);
+ OFDataBufferAppendByte(_dataBuffer, ' ');
+ _state.foregroundColorIndex = newColorIndex;
+ }
+
+ newColor = [newAttributes objectForKey:OABackgroundColorAttributeName];
+ colorTableEntry = [[OUIRTFColorTableEntry alloc] initWithColor:newColor];
+ newColorIndexValue = [_registeredColors objectForKey:colorTableEntry];
+ [colorTableEntry release];
+ OBASSERT(newColorIndexValue != nil);
+ newColorIndex = [newColorIndexValue intValue];
+
+ if (newColorIndex != _state.backgroundColorIndex) {
+ OFDataBufferAppendCString(_dataBuffer, "\\cb");
+ OFDataBufferAppendInteger(_dataBuffer, newColorIndex);
+ OFDataBufferAppendByte(_dataBuffer, ' ');
+ _state.backgroundColorIndex = newColorIndex;
+ }
}
- (void)_writeParagraphAttributes:(NSDictionary *)newAttributes;
@@ -327,10 +343,12 @@ - (void)_writeColorTable;
[defaultColorEntry writeToDataBuffer:_dataBuffer];
[defaultColorEntry release];
- NSRange effectiveRange;
NSUInteger stringLength = [_attributedString length];
- for (NSUInteger textIndex = 0; textIndex < stringLength; textIndex = NSMaxRange(effectiveRange)) {
- id color = [_attributedString attribute:(NSString *)kCTForegroundColorAttributeName atIndex:textIndex effectiveRange:&effectiveRange];
+ NSSet *textColors = [_attributedString valuesOfAttribute:(NSString *)kCTForegroundColorAttributeName inRange:(NSRange){0, stringLength}];
+ textColors = [textColors setByAddingObjectsFromSet:[_attributedString valuesOfAttribute:OABackgroundColorAttributeName inRange:(NSRange){0, stringLength}]];
+ for (id color in textColors) {
+ if (!color || [color isNull])
+ continue;
#ifdef DEBUG_RTF_WRITER
NSLog(@"Registering color: %@", [OUIRTFWriter debugStringForColor:color]);
#endif
@@ -460,7 +478,9 @@ - (id)initWithColor:(id)color;
if (color == nil)
return self;
-
+
+ OBASSERT(CFGetTypeID(color) == CGColorGetTypeID());
+
CGColorRef cgColor = (CGColorRef)color;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor);
const CGFloat *components = CGColorGetComponents(cgColor);

0 comments on commit eae6fc0

Please sign in to comment.