Skip to content

Commit

Permalink
Implement CTRunGetTextMatrix and CTRunGetStatus (#1985)
Browse files Browse the repository at this point in the history
Fixes #1982
  • Loading branch information
aballway authored Feb 17, 2017
1 parent dca9d00 commit 9b071a3
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
36 changes: 28 additions & 8 deletions Frameworks/CoreText/CTRun.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
#import "DWriteWrapper_CoreText.h"
#import "CoreTextInternal.h"
#import "CGContextInternal.h"
#import <CppUtils.h>

#include <numeric>
#include <algorithm>
#include <functional>

const CFStringRef kCTBackgroundStrokeColorAttributeName = static_cast<CFStringRef>(@"kCTBackgroundStrokeColorAttributeName");
const CFStringRef kCTBackgroundFillColorAttributeName = static_cast<CFStringRef>(@"kCTBackgroundFillColorAttributeName");
Expand All @@ -45,6 +48,7 @@ - (void)dealloc {
- (id)init {
if (self = [super init]) {
_attributes.attach([NSMutableDictionary new]);
_textMatrix = CGAffineTransformIdentity;
}

return self;
Expand Down Expand Up @@ -95,12 +99,29 @@ CFDictionaryRef CTRunGetAttributes(CTRunRef run) {
}

/**
@Status Stub
@Status Interoperable
@Notes
*/
CTRunStatus CTRunGetStatus(CTRunRef run) {
UNIMPLEMENTED();
return StubReturn();
CTRunStatus CTRunGetStatus(CTRunRef runRef) {
CTRunStatus ret = kCTRunStatusNoStatus;
if (runRef) {
_CTRun* run = static_cast<_CTRun*>(runRef);

if (run->_dwriteGlyphRun.bidiLevel & 1) {
ret |= kCTRunStatusRightToLeft;
if (!std::is_sorted(run->_stringIndices.cbegin(), run->_stringIndices.cend(), std::greater<UINT16>())) {
ret |= kCTRunStatusNonMonotonic;
}
} else if (!std::is_sorted(run->_stringIndices.cbegin(), run->_stringIndices.cend())) {
ret |= kCTRunStatusNonMonotonic;
}

if (run->_textMatrix != CGAffineTransformIdentity) {
ret |= kCTRunStatusHasNonIdentityMatrix;
}
}

return ret;
}

/**
Expand Down Expand Up @@ -294,12 +315,11 @@ void CTRunDraw(CTRunRef run, CGContextRef ctx, CFRange textRange) {
}

/**
@Status Stub
@Notes
@Status Caveat
@Notes CTRunRef will only ever have CGAffineTransformIdentity until #1987
*/
CGAffineTransform CTRunGetTextMatrix(CTRunRef run) {
UNIMPLEMENTED();
return StubReturn();
return run ? static_cast<_CTRun*>(run)->_textMatrix : CGAffineTransformIdentity;
}

/**
Expand Down
1 change: 1 addition & 0 deletions Frameworks/include/CGContextInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ COREGRAPHICS_EXPORT void _CGContextPushBeginDraw(CGContextRef ctx);
COREGRAPHICS_EXPORT void _CGContextPopEndDraw(CGContextRef ctx);

// Struct used to hold information about glyph run for drawing in _CGContextDrawGlyphRuns
// TODO #1987: Add support for CTRun text matrix
struct GlyphRunData {
DWRITE_GLYPH_RUN* run;
CGPoint relativePosition;
Expand Down
1 change: 1 addition & 0 deletions Frameworks/include/CoreTextInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ inline void _SafeRelease(T** p) {
CGFloat _relativeYOffset;
std::vector<CGSize> _glyphAdvances;
std::vector<CGPoint> _glyphOrigins;
CGAffineTransform _textMatrix;
}
@end

Expand Down
6 changes: 5 additions & 1 deletion Frameworks/include/CppUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ std::basic_ostream<T>& operator<<(std::basic_ostream<T>& os, const CGSize& size)
}

inline CGSize operator*(const CGSize& lhs, CGFloat multiplier) {
return{ lhs.width * multiplier, lhs.height * multiplier };
return { lhs.width * multiplier, lhs.height * multiplier };
}

#pragma endregion
Expand All @@ -82,6 +82,10 @@ inline bool operator==(const CGAffineTransform lhs, const CGAffineTransform& rhs
return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c && lhs.d == rhs.d && lhs.tx == rhs.tx && lhs.ty == rhs.ty;
}

inline bool operator!=(const CGAffineTransform lhs, const CGAffineTransform& rhs) {
return !(lhs == rhs);
}

template <typename T>
std::basic_ostream<T>& operator<<(std::basic_ostream<T>& os, const CGAffineTransform& t) {
os << "a: " << t.a << " b: " << t.b << " c: " << t.c << " d: " << t.d << " tx: " << t.tx << " ty: " << t.ty;
Expand Down
5 changes: 3 additions & 2 deletions include/CoreText/CTRun.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ enum {

CORETEXT_EXPORT CFIndex CTRunGetGlyphCount(CTRunRef run);
CORETEXT_EXPORT CFDictionaryRef CTRunGetAttributes(CTRunRef run);
CORETEXT_EXPORT CTRunStatus CTRunGetStatus(CTRunRef run) STUB_METHOD;
CORETEXT_EXPORT CTRunStatus CTRunGetStatus(CTRunRef run);
CORETEXT_EXPORT const CGGlyph* CTRunGetGlyphsPtr(CTRunRef run);
CORETEXT_EXPORT void CTRunGetGlyphs(CTRunRef run, CFRange range, CGGlyph buffer[]);
CORETEXT_EXPORT const CGPoint* CTRunGetPositionsPtr(CTRunRef run);
Expand All @@ -48,5 +48,6 @@ CORETEXT_EXPORT CFRange CTRunGetStringRange(CTRunRef run);
CORETEXT_EXPORT double CTRunGetTypographicBounds(CTRunRef run, CFRange range, CGFloat* ascent, CGFloat* descent, CGFloat* leading);
CORETEXT_EXPORT CGRect CTRunGetImageBounds(CTRunRef run, CGContextRef context, CFRange range) STUB_METHOD;
CORETEXT_EXPORT void CTRunDraw(CTRunRef run, CGContextRef context, CFRange range);
CORETEXT_EXPORT CGAffineTransform CTRunGetTextMatrix(CTRunRef run) STUB_METHOD;
CORETEXT_EXPORT CGAffineTransform CTRunGetTextMatrix(CTRunRef run);
CORETEXT_EXPORT CFTypeID CTRunGetTypeID() STUB_METHOD;
CORETEXT_EXPORT CFTypeID CTRunGetTypeID() NOTINPLAN_METHOD;
33 changes: 32 additions & 1 deletion tests/unittests/CoreText/CTRunTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#import <Foundation/Foundation.h>
#import <CoreText/CoreText.h>
#import <CoreFoundation/CFAttributedString.h>
#import <CppUtils.h>

#include <functional>

Expand Down Expand Up @@ -347,4 +348,34 @@ virtual void TearDown() {
EXPECT_EQ(std::round(43.1641), std::round((positionsPtr + 5)->y));

CFRelease(line);
}
}

TEST(CTRun, GetTextMatrix) {
EXPECT_EQ(CGAffineTransformIdentity, CTRunGetTextMatrix(nullptr));

CFMutableAttributedStringRef string = (__bridge CFMutableAttributedStringRef)getString(@"foobar");
CFAttributedStringSetAttribute(string, CFRangeMake(0, 3), kCTForegroundColorAttributeName, CGColorGetConstantColor(kCGColorWhite));
auto line = woc::MakeAutoCF<CTLineRef>(CTLineCreateWithAttributedString(string));
CFArrayRef runsArray = CTLineGetGlyphRuns(line);
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runsArray, 0);
EXPECT_EQ(CGAffineTransformIdentity, CTRunGetTextMatrix(run));

run = (CTRunRef)CFArrayGetValueAtIndex(runsArray, 1);
EXPECT_EQ(CGAffineTransformIdentity, CTRunGetTextMatrix(run));
}

TEST(CTRun, GetStatus) {
EXPECT_EQ(kCTRunStatusNoStatus, CTRunGetStatus(nullptr));

CFAttributedStringRef string = (__bridge CFAttributedStringRef)getString(@"foobar");
auto line = woc::MakeAutoCF<CTLineRef>(CTLineCreateWithAttributedString(string));
CFArrayRef runsArray = CTLineGetGlyphRuns(line);
CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runsArray, 0);
EXPECT_EQ(kCTRunStatusNoStatus, CTRunGetStatus(run));

string = (__bridge CFAttributedStringRef)getString(@"نص اختبار");
line = woc::MakeAutoCF<CTLineRef>(CTLineCreateWithAttributedString(string));
runsArray = CTLineGetGlyphRuns(line);
run = (CTRunRef)CFArrayGetValueAtIndex(runsArray, 0);
EXPECT_EQ(kCTRunStatusRightToLeft | kCTRunStatusNonMonotonic, CTRunGetStatus(run));
}

0 comments on commit 9b071a3

Please sign in to comment.