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
4 changes: 4 additions & 0 deletions iosMath.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
4987307617D546800041B02B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49965F0117CBBA2700A555C5 /* Foundation.framework */; };
498730A417D547450041B02B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 49965F2617CBBA2700A555C5 /* InfoPlist.strings */; };
498730A717D548190041B02B /* MTMathListBuilderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 49B83EEF17CE71AC0014B739 /* MTMathListBuilderTest.m */; };
C01DEC0DE20260612000001 /* MTColorDecoderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C01DEC0DE20260612000002 /* MTColorDecoderTest.m */; };
498730A817D548190041B02B /* MTMathListTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 49B83EF517CF046A0014B739 /* MTMathListTest.m */; };
498730A917D548CA0041B02B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49965EFF17CBBA2700A555C5 /* UIKit.framework */; };
498730AA17D548D40041B02B /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49B83EF217CE74620014B739 /* CoreText.framework */; };
Expand Down Expand Up @@ -101,6 +102,7 @@
49965F2717CBBA2700A555C5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
49A27B0218EBF5B30030B7EF /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
49B83EEF17CE71AC0014B739 /* MTMathListBuilderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTMathListBuilderTest.m; sourceTree = "<group>"; };
C01DEC0DE20260612000002 /* MTColorDecoderTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTColorDecoderTest.m; sourceTree = "<group>"; };
49B83EF217CE74620014B739 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
49B83EF517CF046A0014B739 /* MTMathListTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTMathListTest.m; sourceTree = "<group>"; };
49B83EF817CF2AE90014B739 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = example/AppDelegate.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -247,6 +249,7 @@
isa = PBXGroup;
children = (
49B83EEF17CE71AC0014B739 /* MTMathListBuilderTest.m */,
C01DEC0DE20260612000002 /* MTColorDecoderTest.m */,
49B83EF517CF046A0014B739 /* MTMathListTest.m */,
490465BE1D23DA8400F82033 /* MTTypesetterTest.m */,
490465C01D23DA8400F82033 /* MTFontManagerTest.m */,
Expand Down Expand Up @@ -513,6 +516,7 @@
buildActionMask = 2147483647;
files = (
498730A717D548190041B02B /* MTMathListBuilderTest.m in Sources */,
C01DEC0DE20260612000001 /* MTColorDecoderTest.m in Sources */,
498730A817D548190041B02B /* MTMathListTest.m in Sources */,
490465BF1D23DA8400F82033 /* MTTypesetterTest.m in Sources */,
490465C11D23DA8400F82033 /* MTFontManagerTest.m in Sources */,
Expand Down
18 changes: 12 additions & 6 deletions iosMath/render/NSColor+HexString.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ + (NSColor *)colorFromHexString:(NSString *)hexString {
return nil;
}

unsigned rgbValue = 0;

NSScanner *scanner = [NSScanner scannerWithString:hexString];
if ([hexString characterAtIndex:0] == '#') {
[scanner setScanLocation:1];
// Drop the leading '#'.
NSString *hex = [hexString substringFromIndex:1];

// Expand CSS 3-digit shorthand #RGB → #RRGGBB (e.g. "f00" → "ff0000").
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
hex = [NSString stringWithFormat:@"%C%C%C%C%C%C", r, r, g, g, b, b];
}
Comment on lines +27 to 32

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using stringWithFormat: with multiple %C format specifiers introduces unnecessary overhead because it requires parsing the format string at runtime. Since we are just duplicating characters to form a 6-character string, we can use stringWithCharacters:length: with a local stack array. This is significantly faster and more memory-efficient.

Suggested change
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
hex = [NSString stringWithFormat:@"%C%C%C%C%C%C", r, r, g, g, b, b];
}
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
unichar chars[6] = {r, r, g, g, b, b};
hex = [NSString stringWithCharacters:chars length:6];
}



unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hex];
[scanner scanHexInt:&rgbValue];
// NOTE: red:green:blue:alpha: in AppKit/NSColor.h is NS_AVAILABLE_MAC(10_9), unavailable for macOS 10.8 .
// Older method name colorWithSRGBRed::green:blue:alpha: works.
Expand Down
18 changes: 12 additions & 6 deletions iosMath/render/UIColor+HexString.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,19 @@ + (UIColor *)colorFromHexString:(NSString *)hexString {
return nil;
}

unsigned rgbValue = 0;

NSScanner *scanner = [NSScanner scannerWithString:hexString];
if ([hexString characterAtIndex:0] == '#') {
[scanner setScanLocation:1];
// Drop the leading '#'.
NSString *hex = [hexString substringFromIndex:1];

// Expand CSS 3-digit shorthand #RGB → #RRGGBB (e.g. "f00" → "ff0000").
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
hex = [NSString stringWithFormat:@"%C%C%C%C%C%C", r, r, g, g, b, b];
}
Comment on lines +28 to 33

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using stringWithFormat: with multiple %C format specifiers introduces unnecessary overhead because it requires parsing the format string at runtime. Since we are just duplicating characters to form a 6-character string, we can use stringWithCharacters:length: with a local stack array. This is significantly faster and more memory-efficient.

Suggested change
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
hex = [NSString stringWithFormat:@"%C%C%C%C%C%C", r, r, g, g, b, b];
}
if (hex.length == 3) {
unichar r = [hex characterAtIndex:0];
unichar g = [hex characterAtIndex:1];
unichar b = [hex characterAtIndex:2];
unichar chars[6] = {r, r, g, g, b, b};
hex = [NSString stringWithCharacters:chars length:6];
}



unsigned rgbValue = 0;
NSScanner *scanner = [NSScanner scannerWithString:hex];
[scanner scanHexInt:&rgbValue];
return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:1.0];
}
Expand Down
89 changes: 89 additions & 0 deletions iosMathTests/MTColorDecoderTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// MTColorDecoderTest.m
// iosMath
//
// Tests for UIColor(HexString) / NSColor(HexString) colorFromHexString:.
// REN-7: 3-digit CSS shorthand #RGB should expand to #RRGGBB before decoding.
//

@import XCTest;

#if TARGET_OS_IPHONE
#import "UIColor+HexString.h"
#define MTTestColor UIColor
#else
#import "NSColor+HexString.h"
#define MTTestColor NSColor
#endif

@interface MTColorDecoderTest : XCTestCase
@end

@implementation MTColorDecoderTest

// Helper: extract red/green/blue components in the 0–255 integer range.
- (void)assertColor:(MTTestColor *)color red:(int)expectedR green:(int)expectedG blue:(int)expectedB msg:(NSString *)msg {
XCTAssertNotNil(color, @"%@", msg);
CGFloat r = 0, g = 0, b = 0, a = 0;
#if TARGET_OS_IPHONE
[color getRed:&r green:&g blue:&b alpha:&a];
#else
// NSColor is created with colorWithSRGBRed:; retrieve components in sRGB.
MTTestColor *srgb = [color colorUsingColorSpace:[NSColorSpace sRGBColorSpace]];
[srgb getRed:&r green:&g blue:&b alpha:&a];
#endif
XCTAssertEqual((int)round(r * 255), expectedR, @"red — %@", msg);
XCTAssertEqual((int)round(g * 255), expectedG, @"green — %@", msg);
XCTAssertEqual((int)round(b * 255), expectedB, @"blue — %@", msg);
}

// REN-7 regression: #f00 must decode to pure red, not near-black green.
- (void)testThreeDigit_red {
MTTestColor *color = [MTTestColor colorFromHexString:@"#f00"];
[self assertColor:color red:255 green:0 blue:0 msg:@"#f00 should be pure red"];
}

// Additional 3-digit forms.
- (void)testThreeDigit_green {
MTTestColor *color = [MTTestColor colorFromHexString:@"#0f0"];
[self assertColor:color red:0 green:255 blue:0 msg:@"#0f0 should be pure green"];
}

- (void)testThreeDigit_blue {
MTTestColor *color = [MTTestColor colorFromHexString:@"#00f"];
[self assertColor:color red:0 green:0 blue:255 msg:@"#00f should be pure blue"];
}

- (void)testThreeDigit_white {
MTTestColor *color = [MTTestColor colorFromHexString:@"#fff"];
[self assertColor:color red:255 green:255 blue:255 msg:@"#fff should be white"];
}

- (void)testThreeDigit_black {
MTTestColor *color = [MTTestColor colorFromHexString:@"#000"];
[self assertColor:color red:0 green:0 blue:0 msg:@"#000 should be black"];
}

// 6-digit paths must be unaffected (no regression).
- (void)testSixDigit_red {
MTTestColor *color = [MTTestColor colorFromHexString:@"#ff0000"];
[self assertColor:color red:255 green:0 blue:0 msg:@"#ff0000 should be pure red"];
}

- (void)testSixDigit_green {
MTTestColor *color = [MTTestColor colorFromHexString:@"#00ff00"];
[self assertColor:color red:0 green:255 blue:0 msg:@"#00ff00 should be pure green"];
}

- (void)testSixDigit_blue {
MTTestColor *color = [MTTestColor colorFromHexString:@"#0000ff"];
[self assertColor:color red:0 green:0 blue:255 msg:@"#0000ff should be pure blue"];
}

- (void)testSixDigit_arbitrary {
// #4a9 shorthand → #44aa99; full form #44aa99 should match.
MTTestColor *color = [MTTestColor colorFromHexString:@"#44aa99"];
[self assertColor:color red:0x44 green:0xaa blue:0x99 msg:@"#44aa99 arbitrary 6-digit"];
}

@end
Loading