├── .circleci └── config.yml ├── .gitignore ├── .travis.yml ├── Configurations ├── AllTests.xcconfig ├── Debug.xcconfig ├── Demo.xcconfig ├── Framework.xcconfig ├── Release.xcconfig ├── STULabel static.xcconfig ├── STULabel.xcconfig ├── STULabelResources.xcconfig ├── STULabelSwift static.xcconfig ├── STULabelSwift.xcconfig ├── Shared.xcconfig ├── Static.xcconfig └── Tests.xcconfig ├── Demo ├── AppDelegate.swift ├── AutoHeightTableViewCell.swift ├── Demo-Bridging-Header.h ├── Demo.entitlements ├── Features │ ├── TapToReadMoreVC.swift │ └── UDHRViewerVC.swift ├── FormCells.swift ├── Info.plist ├── LabelView.swift ├── Performance │ ├── LabelPerformanceVC.swift │ ├── TableViewPerformanceVC.swift │ ├── TextFramePerformanceVC-Drawing.h │ ├── TextFramePerformanceVC-Drawing.m │ ├── TextFramePerformanceVC.swift │ └── TimingResultView.swift ├── Resources │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── toggle-icon.imageset │ │ │ ├── Contents.json │ │ │ └── toggle.pdf │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── LICENSE.txt │ └── udhr.html ├── RootViewController.swift ├── UDHR.swift └── Utils │ ├── AttributedStringUtils.swift │ ├── AutoLayoutUtils.swift │ ├── CoreGraphicsUtils.swift │ ├── DictionaryExtension.swift │ ├── Fonts.swift │ ├── Rand.swift │ ├── Setting.swift │ ├── StaticTableViewController.swift │ ├── Stats.swift │ ├── StringExtension.swift │ ├── UIColorExtension.swift │ ├── UIEdgeInsetsExtension.swift │ ├── UILabelWithContentInsets.swift │ └── UIViewExtension.swift ├── LICENSE.txt ├── Makefile ├── README.md ├── STULabel.podspec ├── STULabel.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ ├── Demo.xcscheme │ ├── STULabel static.xcscheme │ ├── STULabel.xcscheme │ ├── STULabelSwift static.xcscheme │ └── STULabelSwift.xcscheme ├── STULabel ├── Info.plist ├── Internal │ ├── AtomicEnum.hpp │ ├── CancellationFlag.hpp │ ├── CancellationFlag.mm │ ├── Color-no-ARC.mm │ ├── Color.hpp │ ├── Color.mm │ ├── Common.hpp │ ├── CoreAnimationUtils.hpp │ ├── CoreAnimationUtils.mm │ ├── CoreGraphicsUtils.hpp │ ├── CoreGraphicsUtils.mm │ ├── DecorationLines.hpp │ ├── DecorationLines.mm │ ├── DefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h │ ├── DisplayScaleRounding.hpp │ ├── DisplayScaleRounding.mm │ ├── DrawingContext.hpp │ ├── DrawingContext.mm │ ├── Equal.hpp │ ├── Font.hpp │ ├── Font.mm │ ├── GlyphPathIntersectionBounds.hpp │ ├── GlyphPathIntersectionBounds.mm │ ├── GlyphSpan.hpp │ ├── GlyphSpan.mm │ ├── Hash.hpp │ ├── HashTable.hpp │ ├── HashTable.mm │ ├── InputClamping.hpp │ ├── IntervalSearchTable.hpp │ ├── IntervalSearchTable.mm │ ├── Kerning.hpp │ ├── Kerning.mm │ ├── LabelParameters.hpp │ ├── LabelParameters.mm │ ├── LabelPrerenderer.hpp │ ├── LabelPrerenderer.mm │ ├── LabelRenderTask.hpp │ ├── LabelRenderTask.mm │ ├── LabelRendering.hpp │ ├── LabelRendering.mm │ ├── LayerVisibleBoundsObserver.hpp │ ├── LayerVisibleBoundsObserver.mm │ ├── LineTruncation.hpp │ ├── LineTruncation.mm │ ├── Localized.hpp │ ├── Localized.mm │ ├── NSArrayRef-no-ARC.mm │ ├── NSArrayRef.hpp │ ├── NSAttributedString-no-ARC.mm │ ├── NSAttributedStringRef.hpp │ ├── NSCoderUtils.hpp │ ├── NSStringRef.hpp │ ├── NSStringRef.mm │ ├── Once.hpp │ ├── PurgeableImage.hpp │ ├── PurgeableImage.mm │ ├── Rect.hpp │ ├── STULabelAddToContactsViewController.h │ ├── STULabelAddToContactsViewController.m │ ├── STULabelGhostingMaskLayer.h │ ├── STULabelGhostingMaskLayer.mm │ ├── STULabelLinkOverlayLayer.h │ ├── STULabelLinkOverlayLayer.m │ ├── STULabelSubrangeView.h │ ├── STULabelSubrangeView.mm │ ├── STULabelTiledLayer.h │ ├── STULabelTiledLayer.mm │ ├── STUMediaTimingFunctionUtils.h │ ├── STUPlaceholderObjects-no-ARC.m │ ├── STUPlaceholderObjects.h │ ├── ShapedString.hpp │ ├── ShapedString.mm │ ├── SortedIntervalBuffer.hpp │ ├── SortedIntervalBuffer.mm │ ├── StyledStringRangeIteration.hpp │ ├── StyledStringRangeIteration.mm │ ├── TextFlags.hpp │ ├── TextFrame-Background.mm │ ├── TextFrame-Drawing.mm │ ├── TextFrame-IndexConversion.mm │ ├── TextFrame-PointToIndex.mm │ ├── TextFrame-TruncatedAttributedString.mm │ ├── TextFrame.hpp │ ├── TextFrame.mm │ ├── TextFrameCompactIndex.hpp │ ├── TextFrameDrawingOptions.hpp │ ├── TextFrameLayouter-LineBreaking.mm │ ├── TextFrameLayouter-LineTruncation.mm │ ├── TextFrameLayouter-Scaling.mm │ ├── TextFrameLayouter.hpp │ ├── TextFrameLayouter.mm │ ├── TextFrameLine-Drawing.mm │ ├── TextFrameLine-FontMetric.mm │ ├── TextFrameLine-GlyphSpanIteration.mm │ ├── TextFrameLine-ImageBounds.mm │ ├── TextLineSpan.hpp │ ├── TextLineSpan.mm │ ├── TextLineSpansPath.hpp │ ├── TextLineSpansPath.mm │ ├── TextStyle.hpp │ ├── TextStyle.mm │ ├── TextStyleBuffer.hpp │ ├── TextStyleBuffer.mm │ ├── ThreadLocalAllocator.hpp │ ├── ThreadLocalAllocator.mm │ ├── UndefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h │ ├── UnicodeCodePointProperties.hpp │ ├── UnicodeCodePointProperties.mm │ ├── Unretained.hpp │ └── stu │ │ ├── Allocation.cpp │ │ ├── Allocation.hpp │ │ ├── ArenaAllocator.cpp │ │ ├── ArenaAllocator.hpp │ │ ├── Array.hpp │ │ ├── ArrayRef.hpp │ │ ├── ArrayUtils.hpp │ │ ├── Assert.h │ │ ├── Assert.m │ │ ├── BinarySearch.hpp │ │ ├── Casts.hpp │ │ ├── Comparable.hpp │ │ ├── Config.h │ │ ├── Config.hpp │ │ ├── Dollar.hpp │ │ ├── FunctionRef.hpp │ │ ├── InOut.hpp │ │ ├── Iterator.hpp │ │ ├── MinMax.hpp │ │ ├── NSFoundationSupport.hpp │ │ ├── Optional.cpp │ │ ├── Optional.hpp │ │ ├── OptionsEnum.hpp │ │ ├── Parameter.hpp │ │ ├── Range.hpp │ │ ├── Ref.hpp │ │ ├── RefCounting.hpp │ │ ├── ScopeGuard.hpp │ │ ├── TypeTraits.hpp │ │ ├── UniquePtr.hpp │ │ ├── Utility.hpp │ │ ├── Vector.cpp │ │ ├── Vector.hpp │ │ ├── module.modulemap │ │ └── stu_lldb_formatters.py ├── NSAttributedString+STUDynamicTypeFontScaling.h ├── NSAttributedString+STUDynamicTypeFontScaling.m ├── NSLayoutAnchor+STULabelSpacing.h ├── Resources │ ├── Info.plist │ ├── ar.lproj │ │ └── Localizable.strings │ ├── ca.lproj │ │ └── Localizable.strings │ ├── cs.lproj │ │ └── Localizable.strings │ ├── da.lproj │ │ └── Localizable.strings │ ├── de.lproj │ │ └── Localizable.strings │ ├── el.lproj │ │ └── Localizable.strings │ ├── en.lproj │ │ └── Localizable.strings │ ├── es-419.lproj │ │ └── Localizable.strings │ ├── es.lproj │ │ └── Localizable.strings │ ├── fi.lproj │ │ └── Localizable.strings │ ├── fr-CA.lproj │ │ └── Localizable.strings │ ├── fr.lproj │ │ └── Localizable.strings │ ├── he.lproj │ │ └── Localizable.strings │ ├── hi.lproj │ │ └── Localizable.strings │ ├── hr.lproj │ │ └── Localizable.strings │ ├── hu.lproj │ │ └── Localizable.strings │ ├── id.lproj │ │ └── Localizable.strings │ ├── it.lproj │ │ └── Localizable.strings │ ├── ja.lproj │ │ └── Localizable.strings │ ├── ko.lproj │ │ └── Localizable.strings │ ├── ms.lproj │ │ └── Localizable.strings │ ├── nb.lproj │ │ └── Localizable.strings │ ├── nl.lproj │ │ └── Localizable.strings │ ├── pl.lproj │ │ └── Localizable.strings │ ├── pt-PT.lproj │ │ └── Localizable.strings │ ├── pt.lproj │ │ └── Localizable.strings │ ├── ro.lproj │ │ └── Localizable.strings │ ├── ru.lproj │ │ └── Localizable.strings │ ├── sk.lproj │ │ └── Localizable.strings │ ├── sv.lproj │ │ └── Localizable.strings │ ├── th.lproj │ │ └── Localizable.strings │ ├── tr.lproj │ │ └── Localizable.strings │ ├── uk.lproj │ │ └── Localizable.strings │ ├── vi.lproj │ │ └── Localizable.strings │ ├── zh-Hans.lproj │ │ └── Localizable.strings │ ├── zh-Hant-HK.lproj │ │ └── Localizable.strings │ └── zh-Hant.lproj │ │ └── Localizable.strings ├── STUBackgroundAttribute-Internal.h ├── STUBackgroundAttribute.h ├── STUBackgroundAttribute.mm ├── STUCancellationFlag.h ├── STUDefines.h ├── STUImageUtils.h ├── STUImageUtils.m ├── STULabel.h ├── STULabel.mm ├── STULabel.modulemap ├── STULabelAlignment.h ├── STULabelDrawingBlock-Internal.hpp ├── STULabelDrawingBlock.h ├── STULabelDrawingBlock.mm ├── STULabelLayer-Internal.hpp ├── STULabelLayer.h ├── STULabelLayer.mm ├── STULabelLayoutInfo-Internal.hpp ├── STULabelLayoutInfo.h ├── STULabelLayoutInfo.mm ├── STULabelOverlayStyle.h ├── STULabelOverlayStyle.mm ├── STULabelPrerenderer-Internal.hpp ├── STULabelPrerenderer-no-ARC.mm ├── STULabelPrerenderer.h ├── STULabelPrerenderer.mm ├── STULabelSwiftExtensions.h ├── STULayerWithNullDefaultActions.h ├── STULayerWithNullDefaultActions.m ├── STUMainScreenProperties.h ├── STUMainScreenProperties.m ├── STUObjCRuntimeWrappers-no-ARC.m ├── STUObjCRuntimeWrappers.h ├── STUParagraphStyle-Internal.hpp ├── STUParagraphStyle.h ├── STUParagraphStyle.mm ├── STUShapedString-Internal.hpp ├── STUShapedString.h ├── STUShapedString.mm ├── STUStartEndRange-Internal.hpp ├── STUStartEndRange.h ├── STUTextAttachment-Internal.hpp ├── STUTextAttachment.h ├── STUTextAttachment.mm ├── STUTextAttributes-Internal.hpp ├── STUTextAttributes.h ├── STUTextAttributes.mm ├── STUTextFlags.h ├── STUTextFrame-Internal.hpp ├── STUTextFrame-Unsafe.h ├── STUTextFrame.h ├── STUTextFrame.mm ├── STUTextFrameAccessibilityElement.h ├── STUTextFrameAccessibilityElement.mm ├── STUTextFrameDrawingOptions-Internal.hpp ├── STUTextFrameDrawingOptions.h ├── STUTextFrameDrawingOptions.mm ├── STUTextFrameLine.h ├── STUTextFrameLine.mm ├── STUTextFrameOptions-Internal.hpp ├── STUTextFrameOptions.h ├── STUTextFrameOptions.mm ├── STUTextFrameRange.h ├── STUTextHighlightStyle-Internal.hpp ├── STUTextHighlightStyle.h ├── STUTextHighlightStyle.mm ├── STUTextLink-Internal.hpp ├── STUTextLink.h ├── STUTextLink.mm ├── STUTextRange.h ├── STUTextRectArray-Internal.hpp ├── STUTextRectArray.h ├── STUTextRectArray.mm ├── STUTruncationScope-Internal.h ├── STUTruncationScope.h ├── STUTruncationScope.mm ├── UIFont+STUDynamicTypeFontScaling.h ├── UIFont+STUDynamicTypeFontScaling.m ├── stu_label_lldb_formatters.py ├── stu_mutex.c └── stu_mutex.h ├── STULabelSwift.podspec ├── STULabelSwift ├── Info.plist ├── Internal │ └── RoundToScale.swift ├── NSLayoutAnchor+STULabelSpacing.overlay.swift ├── STUImageUtils.overlay.swift ├── STULabel.overlay.swift ├── STULabelDrawingBlockParameters.overlay.swift ├── STULabelLayer.overlay.swift ├── STUParagraphStyle.overlay.swift ├── STUStartEndRange.overlay.swift ├── STUTextFrame.overlay.swift ├── STUTextFrameDrawingOptions.overlay.swift ├── STUTextFrameWithOrigin.swift └── STUTextRectArray.overlay.swift └── Tests ├── AutoLayoutTests.swift ├── DynamicTypeFontScalingTests.swift ├── Info.plist ├── Internal ├── AllocatorUtils.hpp ├── DisplayScaleRounding.mm ├── GlyphBoundsCacheTests.mm ├── HashSetTests.mm ├── HashTests.mm ├── NSStringRefTests.mm ├── ReferenceImages │ └── TextLineSpansPathTests │ │ ├── testAddLineSpansPath_1.png │ │ ├── testAddLineSpansPath_1_rounded.png │ │ ├── testAddLineSpansPath_1_rounded_inset_2.png │ │ ├── testAddLineSpansPath_1_rounded_inset_20.png │ │ ├── testAddLineSpansPath_1_rounded_inset_2_32bit.png │ │ ├── testAddLineSpansPath_1_rounded_inset_5.png │ │ ├── testAddLineSpansPath_1_rounded_inset_h5.png │ │ ├── testAddLineSpansPath_1_rounded_inset_v5.png │ │ ├── testAddLineSpansPath_1_rounded_outset_2.png │ │ ├── testAddLineSpansPath_1_rounded_outset_20.png │ │ ├── testAddLineSpansPath_1_rounded_outset_2_32bit.png │ │ ├── testAddLineSpansPath_1_rounded_outset_5.png │ │ └── testAddLineSpansPath_1_rounded_shifted.png ├── SortedIntervalBufferTests.mm ├── TestUtils.h ├── TextLineSpansPathTests.mm ├── TextStyleBufferTests.mm ├── UnicodeCodePointPropertiesTests.mm └── stu │ ├── AllocationTests.cpp │ ├── AllocatorUtils.cpp │ ├── ArenaAllocatorTests.cpp │ ├── ArrayTests.cpp │ ├── ArrayUtilsTests.cpp │ ├── BinarySearchTests.cpp │ ├── FunctionRefTests.cpp │ ├── NSFoundationSupportTests-no-ARC.mm │ ├── NSFoundationSupportTests.mm │ ├── RangeTests.cpp │ ├── TestUtils.hpp │ ├── TestValue.cpp │ ├── TestValue.hpp │ ├── UtilityTests.cpp │ └── VectorTests.cpp ├── LabelAlignmentTests.swift ├── MainScreenPropertiesTests.swift ├── MutexTests.m ├── ParagraphStyleTests.swift ├── ReferenceImages ├── AutoLayoutTests │ ├── testBaselineAnchors_first_last@1.png │ ├── testBaselineAnchors_first_last@2.png │ ├── testBaselineAnchors_first_last@2_32bit_phone.png │ ├── testBaselineAnchors_first_last@3.png │ ├── testBaselineAnchors_last_first@1.png │ ├── testBaselineAnchors_last_first@2.png │ ├── testBaselineAnchors_last_first@2_32bit_phone.png │ ├── testBaselineAnchors_last_first@3.png │ ├── testBaselineAnchors_swapped_first_last@1.png │ ├── testBaselineAnchors_swapped_first_last@2.png │ ├── testBaselineAnchors_swapped_first_last@2_32bit_phone.png │ ├── testBaselineAnchors_swapped_first_last@3.png │ ├── testContentLayoutGuide_1@1.png │ ├── testContentLayoutGuide_1@2.png │ ├── testContentLayoutGuide_1@3.png │ ├── testContentLayoutGuide_2@1.png │ ├── testContentLayoutGuide_2@2.png │ ├── testContentLayoutGuide_2@3.png │ ├── testSpacingAboveAndBelowWithNonLabelAnchor@1.png │ ├── testSpacingAboveAndBelowWithNonLabelAnchor@2.png │ ├── testSpacingAboveAndBelowWithNonLabelAnchor@3.png │ ├── testSpacingConstraints_1@1.png │ ├── testSpacingConstraints_1@2.png │ ├── testSpacingConstraints_1@3.png │ ├── testSpacingConstraints_2@1.png │ ├── testSpacingConstraints_2@2.png │ ├── testSpacingConstraints_2@3.png │ ├── testSpacingConstraints_3@1.png │ ├── testSpacingConstraints_3@2.png │ ├── testSpacingConstraints_3@3.png │ ├── testSpacingConstraints_lineHeight_1@1.png │ ├── testSpacingConstraints_lineHeight_1@2.png │ ├── testSpacingConstraints_lineHeight_1@3.png │ ├── testSpacingConstraints_lineHeight_1_overlay@1.png │ ├── testSpacingConstraints_lineHeight_1_overlay@2.png │ ├── testSpacingConstraints_lineHeight_1_overlay@3.png │ ├── testSpacingConstraints_lineHeight_2@1.png │ ├── testSpacingConstraints_lineHeight_2@2.png │ ├── testSpacingConstraints_lineHeight_2@3.png │ ├── testSpacingConstraints_lineHeight_3@1.png │ ├── testSpacingConstraints_lineHeight_3@2.png │ └── testSpacingConstraints_lineHeight_3@3.png ├── LabelAlignmentTests │ ├── testAlignment_2_ac.png │ ├── testAlignment_2_al.png │ ├── testAlignment_2_ar.png │ ├── testAlignment_2_bc.png │ ├── testAlignment_2_bl.png │ ├── testAlignment_2_br.png │ ├── testAlignment_2_cc.png │ ├── testAlignment_2_cl.png │ ├── testAlignment_2_cr.png │ ├── testAlignment_2_tc.png │ ├── testAlignment_2_tl.png │ ├── testAlignment_2_tr.png │ ├── testAlignment_2_xc.png │ ├── testAlignment_2_xl.png │ ├── testAlignment_2_xr.png │ ├── testAlignment_ac.png │ ├── testAlignment_al.png │ ├── testAlignment_ar.png │ ├── testAlignment_bc.png │ ├── testAlignment_bl.png │ ├── testAlignment_br.png │ ├── testAlignment_cc.png │ ├── testAlignment_cl.png │ ├── testAlignment_cr.png │ ├── testAlignment_tc.png │ ├── testAlignment_tl.png │ ├── testAlignment_tr.png │ ├── testAlignment_xc.png │ ├── testAlignment_xl.png │ └── testAlignment_xr.png ├── TextAttachmentTests │ ├── testAttachmentConversion.png │ ├── testAttachmentConversion_32bit.png │ ├── testAttachmentsInTruncationToken.png │ ├── testAttachmentsInTruncationToken_32bit.png │ ├── testImageAttachmentInitializerAndEncode.png │ ├── testImageAttachmentInitializerAndEncode_iOS10.png │ └── testImageAttachmentInitializerAndEncode_iOS9.png ├── TextFrameDrawingTests │ ├── testBaseCTMHandling.png │ ├── testBaselineRounding.png │ ├── testBaselineRounding_scaled.png │ └── testDrawingIntoPDFContext.pdf ├── TextFrameHighlightingTests │ ├── testHyphenHighlighting_1-3-drawn_hyphen-red.png │ ├── testHyphenHighlighting_all-red.png │ ├── testHyphenHighlighting_black-hyphen-only.png │ ├── testNonMonotonicRunHighlighting_0-4-red.png │ ├── testNonMonotonicRunHighlighting_0-4-red_iOS10.png │ ├── testNonMonotonicRunHighlighting_4-9-drawn_5-6-red.png │ ├── testNonMonotonicRunHighlighting_4-9-drawn_5-6-red_iOS10.png │ ├── testPartialLigatureHighlighting_1-2-red.png │ ├── testPartialLigatureHighlighting_1-4-red.png │ ├── testPartialLigatureHighlighting_1-4-red_32bit.png │ ├── testPartialLigatureHighlighting_1-red.png │ ├── testPartialLigatureHighlighting_1-red_32bit.png │ ├── testPartialLigatureHighlighting_2-3-drawn_2-red.png │ ├── testPartialLigatureHighlighting_2-3-red.png │ ├── testRightToLeftLineHighlighting_2-4-red.png │ ├── testRightToLeftLineHighlighting_2-6-drawn_5-6-red.png │ ├── testTruncatedLineHighlighting_0-1-red.png │ ├── testTruncatedLineHighlighting_2-4-drawn_4-red.png │ ├── testTruncatedLineHighlighting_4-red.png │ ├── testTruncatedLineHighlighting_5-a-drawn_7-red.png │ ├── testTruncatedLineHighlighting_all-red.png │ ├── testTruncatedLineHighlighting_d-red.png │ └── testTruncatedLineHighlighting_no-highlighting.png ├── TextFrameImageBoundsTests │ ├── testPartialLigatureImageBounds_if_with_shadow.png │ ├── testStrokeImageBounds_LL_differently_stroked.png │ ├── testStrokeImageBounds_LL_stroked.png │ ├── testStrokeImageBounds_LL_unstroked.png │ ├── testUnderlineImageBounds_double.png │ ├── testUnderlineImageBounds_shadow_single_thick.png │ └── testUnderlineImageBounds_thick_black_blue_shadow.png ├── TextFrameLineBreakingTests │ ├── testHyphenInMiddleOfLeftToRightRightToLeftLine.png │ ├── testHyphenInRightToLeftLine.png │ ├── testJustificationWithHyphenInLeftToRightRightToLeftLine.png │ ├── testLTRJustification.png │ ├── testRTLJustification.png │ └── testSoftHyphen.png └── TruncationTests │ ├── testSingleCharacterTokenFontSelection_Hoefler.png │ └── testSingleCharacterTokenFontSelection_PingFang.png ├── ShapedStringTests.swift ├── SnapshotTestCase.h ├── SnapshotTestCase.m ├── SnapshotTestCase.swift ├── SwiftWrapperTests.swift ├── TestUtils.swift ├── Tests-Bridging-Header.h ├── TextAttachmentTests.swift ├── TextFrameDrawingTests.swift ├── TextFrameHighlightingTests.swift ├── TextFrameImageBoundsTests.swift ├── TextFrameLayoutInfoTests.swift ├── TextFrameLineBreakingTests.swift ├── TextFrameOptionsTests.swift └── TextFrameTruncationTests.swift /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build-and-test: 4 | macos: 5 | xcode: "10.2.1" 6 | working_directory: /Users/distiller/project 7 | steps: 8 | - run: 9 | name: Install xchtmlreport 10 | command: bash <(curl -s https://raw.githubusercontent.com/TitouanVanBelle/XCTestHTMLReport/master/install.sh) 11 | - checkout 12 | - run: 13 | name: Build static library and tests 14 | command: make build-for-testing 15 | - run: 16 | name: Build demo 17 | command: make demo CONFIGURATION=Release 18 | - run: 19 | name: Run tests on iOS 12 iPad Pro (11-inch) 20 | command: make test-ios12-ipad-pro-11 21 | - run: 22 | name: Run tests on iOS 12 iPhone Xs Max 23 | command: make test-ios12-iphone-xs-max 24 | - run: 25 | name: Run tests on iOS 11 iPad Pro (10.5-inch) 26 | command: make test-ios11-ipad-pro-10_5 27 | - run: 28 | name: Run tests on iOS 11 iPhone X 29 | command: make test-ios11-iphone-x 30 | - run: 31 | name: Run tests on iOS 10 iPad Pro (9.7-inch) 32 | command: make test-ios10-ipad-pro-9_7 33 | - run: 34 | name: Run tests on iOS 10 iPhone 7 Plus 35 | command: make test-ios10-iphone-7-plus 36 | - run: 37 | name: Run xchtmlreport 38 | command: make generate-test-report 39 | - store_test_results: 40 | path: build/results 41 | - store_artifacts: 42 | path: build/results 43 | 44 | workflows: 45 | version: 2 46 | build-and-test: 47 | jobs: 48 | - build-and-test 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Tests/ImageDiffs 2 | build/ 3 | xcuserdata/ 4 | *.xccheckout 5 | *.xcscmblueprint 6 | .idea 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | language: objective-c 3 | xcode_project: STULabel.xcodeproj 4 | osx_image: xcode10.2 5 | 6 | script: 7 | # https://developer.apple.com/documentation/xcode_release_notes/xcode_10_2_1_release_notes?language=objc#3197581 8 | - sudo mkdir '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 9.3.simruntime/Contents/Resources/RuntimeRoot/usr/lib/swift' 9 | - make build-for-testing 10 | - make demo CONFIGURATION=Release LTO=NO 11 | # We only run the tests on the simulator versions not available on CircleCI. 12 | - make test-ios9-iphone-6s 13 | - make test-ios9-iphone-6s-plus 14 | - make test-ios9-ipad-2 15 | -------------------------------------------------------------------------------- /Configurations/AllTests.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "Tests.xcconfig" 3 | 4 | #include "Static.xcconfig" 5 | 6 | USER_HEADER_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/STULabel/Internal 7 | 8 | OTHER_LDFLAGS = $(inherited) -ObjC 9 | -------------------------------------------------------------------------------- /Configurations/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | ONLY_ACTIVE_ARCH = YES 3 | 4 | DEBUG_INFORMATION_FORMAT = dwarf 5 | 6 | COPY_PHASE_STRIP = NO 7 | 8 | GCC_OPTIMIZATION_LEVEL = 0 9 | 10 | SWIFT_COMPILATION_MODE = singlefile 11 | SWIFT_OPTIMIZATION_LEVEL = -Onone 12 | 13 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) DEBUG 14 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) DEBUG=1 15 | 16 | GCC_ENABLE_CPP_EXCEPTIONS = YES 17 | 18 | -------------------------------------------------------------------------------- /Configurations/Demo.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "Shared.xcconfig" 3 | 4 | ONLY_ACTIVE_ARCH = YES 5 | 6 | CODE_SIGN_IDENTITY = iPhone Developer 7 | CODE_SIGN_STYLE = Automatic 8 | 9 | PRODUCT_NAME = $(TARGET_NAME) 10 | PRODUCT_BUNDLE_IDENTIFIER = STULabel.$(PRODUCT_NAME) 11 | 12 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks 13 | 14 | INFOPLIST_FILE = Demo/Info.plist 15 | 16 | SWIFT_OBJC_BRIDGING_HEADER = Demo/Demo-Bridging-Header.h 17 | 18 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon 19 | 20 | CLANG_MODULES_AUTOLINK = NO 21 | 22 | CODE_SIGN_ENTITLEMENTS = Demo/Demo.entitlements 23 | SUPPORTS_MACCATALYST = YES 24 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES 25 | 26 | -------------------------------------------------------------------------------- /Configurations/Framework.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "Shared.xcconfig" 3 | 4 | USE_HEADERMAP = NO 5 | 6 | DYLIB_COMPATIBILITY_VERSION = 1 7 | DYLIB_CURRENT_VERSION = 1 8 | 9 | CURRENT_PROJECT_VERSION = 1 10 | 11 | DYLIB_INSTALL_NAME_BASE = @rpath 12 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 13 | 14 | DEFINES_MODULE = YES 15 | 16 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES 17 | -------------------------------------------------------------------------------- /Configurations/Release.xcconfig: -------------------------------------------------------------------------------- 1 | //ONLY_ACTIVE_ARCH = YES 2 | 3 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym; 4 | 5 | COPY_PHASE_STRIP = NO 6 | 7 | VALIDATE_PRODUCT = YES 8 | 9 | ENABLE_NS_ASSERTIONS = NO 10 | 11 | GCC_OPTIMIZATION_LEVEL = 3 12 | OTHER_CFLAGS = $(inherited) //-fno-unroll-loops 13 | 14 | LLVM_LTO = YES 15 | //OTHER_LDFLAGS = -Xlinker -mllvm -Xlinker -unroll-count=0 -Xlinker -mllvm -Xlinker -disable-lto-vectorization 16 | 17 | SWIFT_COMPILATION_MODE = wholemodule 18 | SWIFT_OPTIMIZATION_LEVEL = -O 19 | 20 | GCC_ENABLE_CPP_EXCEPTIONS = NO 21 | 22 | OTHER_CPLUSPLUSFLAGS = $(inherited) -fno-objc-exceptions -fno-objc-arc-exceptions 23 | 24 | -------------------------------------------------------------------------------- /Configurations/STULabel static.xcconfig: -------------------------------------------------------------------------------- 1 | #include "STULabel.xcconfig" 2 | 3 | #include "Static.xcconfig" 4 | 5 | MACH_O_TYPE = staticlib 6 | -------------------------------------------------------------------------------- /Configurations/STULabel.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Framework.xcconfig" 2 | 3 | PRODUCT_NAME = STULabel 4 | PRODUCT_BUNDLE_IDENTIFIER = STULabel.$(PRODUCT_NAME) 5 | 6 | INFOPLIST_FILE = STULabel/Info.plist 7 | 8 | MODULEMAP_FILE = STULabel/STULabel.modulemap 9 | 10 | USER_HEADER_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/STULabel/Internal 11 | 12 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) STU_IMPLEMENTATION STU_USE_SAFARI_SERVICES=1 13 | -------------------------------------------------------------------------------- /Configurations/STULabelResources.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Shared.xcconfig" 2 | 3 | PRODUCT_NAME = $(TARGET_NAME) 4 | PRODUCT_BUNDLE_IDENTIFIER = STULabel.$(PRODUCT_NAME) 5 | 6 | INFOPLIST_FILE = STULabel/Resources/Info.plist 7 | 8 | WRAPPER_EXTENSION = bundle 9 | -------------------------------------------------------------------------------- /Configurations/STULabelSwift static.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "STULabelSwift.xcconfig" 3 | 4 | #include "Static.xcconfig" 5 | 6 | MACH_O_TYPE = staticlib 7 | -------------------------------------------------------------------------------- /Configurations/STULabelSwift.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "Framework.xcconfig" 3 | 4 | PRODUCT_NAME = STULabelSwift 5 | PRODUCT_BUNDLE_IDENTIFIER = STULabel.$(PRODUCT_NAME) 6 | 7 | INFOPLIST_FILE = STULabelSwift/Info.plist 8 | 9 | SWIFT_INSTALL_OBJC_HEADER = NO 10 | 11 | ENABLE_TESTABILITY = NO 12 | 13 | 14 | -------------------------------------------------------------------------------- /Configurations/Static.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | DEBUG_INFORMATION_FORMAT = dwarf 3 | 4 | CONFIGURATION_BUILD_DIR = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)-static; 5 | CONFIGURATION_TEMP_DIR = $(PROJECT_TEMP_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)-static; 6 | -------------------------------------------------------------------------------- /Configurations/Tests.xcconfig: -------------------------------------------------------------------------------- 1 | 2 | #include "Shared.xcconfig" 3 | 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 5 | 6 | INFOPLIST_FILE = Tests/Info.plist 7 | 8 | PRODUCT_NAME = $(TARGET_NAME) 9 | PRODUCT_BUNDLE_IDENTIFIER = STULabel.$(PRODUCT_NAME) 10 | 11 | SWIFT_OBJC_BRIDGING_HEADER = Tests/Tests-Bridging-Header.h 12 | 13 | OTHER_CPLUSPLUSFLAGS = $(inherited) -fobjc-exceptions 14 | 15 | -------------------------------------------------------------------------------- /Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2017 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | @UIApplicationMain 6 | class AppDelegate: UIResponder, UIApplicationDelegate { 7 | 8 | var window: UIWindow? 9 | 10 | 11 | func application(_ application: UIApplication, 12 | didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) 13 | -> Bool 14 | { 15 | 16 | let window = UIWindow() 17 | 18 | self.window = window 19 | window.backgroundColor = .white 20 | 21 | let navigationVC = UINavigationController(rootViewController: RootViewController()) 22 | 23 | window.rootViewController = navigationVC 24 | 25 | window.makeKeyAndVisible() 26 | 27 | return true 28 | } 29 | } 30 | 31 | 32 | -------------------------------------------------------------------------------- /Demo/AutoHeightTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | class AutoHeightTableViewCell : UITableViewCell { 6 | public override 7 | func systemLayoutSizeFitting(_ targetSize: CGSize, 8 | withHorizontalFittingPriority hPriority: UILayoutPriority, 9 | verticalFittingPriority vPriority: UILayoutPriority) -> CGSize 10 | { 11 | let oldBounds = self.bounds 12 | let needToSetBounds = oldBounds.size.width != targetSize.width 13 | if needToSetBounds { 14 | var bounds = oldBounds 15 | bounds.size.width = targetSize.width 16 | self.bounds = bounds 17 | } 18 | self.layoutIfNeeded() 19 | if needToSetBounds { 20 | self.bounds = oldBounds 21 | } 22 | let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: hPriority, 23 | verticalFittingPriority: vPriority) 24 | return size 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Demo/Demo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "TextFramePerformanceVC-Drawing.h" 4 | 5 | void CGContextSetBaseCTM(CGContextRef c, CGAffineTransform ctm); 6 | 7 | 8 | @interface UIFont (STU_UIFont_NSCoding) 9 | @end 10 | -------------------------------------------------------------------------------- /Demo/Demo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDuration 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIUserInterfaceStyle 45 | Light 46 | 47 | 48 | -------------------------------------------------------------------------------- /Demo/Performance/TextFramePerformanceVC-Drawing.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @import UIKit; 4 | 5 | void drawUsingSTUTextFrame(NSAttributedString *, CGSize, CGPoint offset); 6 | 7 | void drawUsingNSStringDrawing(NSAttributedString *, CGSize, CGPoint offset); 8 | 9 | void measureAndDrawUsingNSStringDrawing(NSAttributedString *, CGSize, CGPoint offset); 10 | 11 | void drawUsingTextKit(NSAttributedString *, CGSize, CGPoint offset); 12 | 13 | void drawUsingCTLine(NSAttributedString *, CGSize, CGPoint offset); 14 | 15 | void drawUsingCTTypesetter(NSAttributedString *, CGSize, CGPoint offset); 16 | 17 | void drawUsingCTFrame(NSAttributedString *, CGSize, CGPoint offset); 18 | -------------------------------------------------------------------------------- /Demo/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/Resources/Assets.xcassets/toggle-icon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "toggle.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "preserves-vector-representation" : true 14 | } 15 | } -------------------------------------------------------------------------------- /Demo/Resources/Assets.xcassets/toggle-icon.imageset/toggle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Demo/Resources/Assets.xcassets/toggle-icon.imageset/toggle.pdf -------------------------------------------------------------------------------- /Demo/Resources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Demo/Resources/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The toggle icon is a converted version of the 'ios-switch-outline' icon from the 2 | Ionic framework icon set available at https://ionicframework.com/docs/ionicons/ 3 | The icon is distributed under the MIT license: 4 | https://github.com/ionic-team/ionicons/blob/master/LICENSE 5 | 6 | The text of the Universal Declaration of Human Rights in UDHR.html is 7 | © 1996 – 2009 The Office of the High Commissioner for Human Rights. 8 | The HTML version is prepared by the 'UDHR in Unicode' project (http://www.unicode.org/udhr) 9 | and distributed under the terms at https://www.unicode.org/copyright.html 10 | -------------------------------------------------------------------------------- /Demo/Utils/AttributedStringUtils.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | func paragraphStyle(_ configure: (NSMutableParagraphStyle) -> ()) -> NSParagraphStyle { 6 | let style = NSMutableParagraphStyle() 7 | configure(style) 8 | return style.copy() as! NSParagraphStyle 9 | } 10 | 11 | let ltrParaStyle = paragraphStyle({b in b.baseWritingDirection = .leftToRight}) 12 | 13 | let rtlParaStyle = paragraphStyle({b in b.baseWritingDirection = .rightToLeft}) 14 | 15 | typealias StringAttributes = [NSAttributedString.Key: Any] 16 | 17 | 18 | extension NSAttributedString { 19 | convenience init(_ string: String, _ attributes: [Key: Any]) { 20 | self.init(string: string, attributes: attributes) 21 | } 22 | 23 | convenience init(_ strings: [(String, StringAttributes)], _ attributes: StringAttributes = [:]) { 24 | let string = NSMutableAttributedString() 25 | for (str, attr) in strings { 26 | string.append(NSAttributedString(str, attr)) 27 | } 28 | string.addAttributes(attributes, range: NSRange(0.. CGPoint { 6 | return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) 7 | } 8 | func -(_ lhs: CGPoint, _ rhs: CGPoint) -> CGPoint { 9 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y) 10 | } 11 | 12 | func += (_ lhs: inout CGPoint, _ rhs: CGPoint) { 13 | lhs = lhs + rhs 14 | } 15 | func -=(_ lhs: inout CGPoint, _ rhs: CGPoint) { 16 | lhs = lhs - rhs 17 | } 18 | 19 | func *(_ s: CGFloat, _ p: CGPoint) -> CGPoint { 20 | return CGPoint(x: s*p.x, y: s*p.y) 21 | } 22 | func *( p: CGPoint, _ s: CGFloat) -> CGPoint { 23 | return s*p 24 | } 25 | func /(_ p: CGPoint, _ s: CGFloat) -> CGPoint { 26 | return CGPoint(x: p.x/s, y: p.y/s) 27 | } 28 | 29 | func *(_ f: CGFloat, _ s: CGSize) -> CGSize { 30 | return CGSize(width: f*s.width, height: f*s.height) 31 | } 32 | func *(_ s: CGSize, _ f: CGFloat) -> CGSize { 33 | return f*s 34 | } 35 | func /(_ s: CGSize, _ f: CGFloat) -> CGSize { 36 | return CGSize(width: s.width/f, height: s.height/f) 37 | } 38 | 39 | 40 | extension CGRect { 41 | var center: CGPoint { 42 | return CGPoint(x: self.origin.x + self.size.width/2, 43 | y: self.origin.y + self.size.height/2) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Demo/Utils/DictionaryExtension.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | extension Dictionary { 4 | mutating func update(with other: Dictionary) { 5 | for (key, value) in other { 6 | self[key] = value 7 | } 8 | } 9 | 10 | func updated(with other: Dictionary) -> Dictionary { 11 | var dict = self 12 | dict.update(with: other) 13 | return dict 14 | } 15 | 16 | func updated(with value: Value, forKey key: Key) -> Dictionary { 17 | var dict = self 18 | dict[key] = value 19 | return dict 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Utils/StaticTableViewController.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | class StaticTableViewController : UITableViewController { 6 | var cells = [UITableViewCell]() { 7 | didSet { 8 | tableView.reloadData() 9 | } 10 | } 11 | 12 | override init(style: UITableView.Style = .plain) { 13 | super.init(style: style) 14 | if #available(iOS 11, tvOS 11, *) {} 15 | else { 16 | tableView.estimatedRowHeight = 57.5 17 | } 18 | } 19 | 20 | @available(*, unavailable) 21 | required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | tableView.alwaysBounceVertical = false 26 | } 27 | 28 | var shouldUpdatePreferredContentSize: Bool = false 29 | var minPreferredContentWidth: CGFloat = 0 30 | 31 | override func viewDidLayoutSubviews() { 32 | super.viewDidLayoutSubviews() 33 | if shouldUpdatePreferredContentSize { 34 | let size = tableView.contentSize 35 | preferredContentSize = CGSize(width: max(size.width, minPreferredContentWidth), 36 | height: size.height) 37 | } 38 | } 39 | 40 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 41 | return section == 0 ? cells.count : 0 42 | } 43 | 44 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) 45 | -> UITableViewCell 46 | { 47 | return cells[indexPath.row] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Demo/Utils/Stats.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import CoreFoundation 4 | 5 | struct Stats { 6 | let count: Int 7 | let min: Double 8 | let max: Double 9 | let mean: Double 10 | let stddev: Double 11 | } 12 | 13 | struct IncremantalStatsCalculator { 14 | private(set) var count: Double = 0 15 | private(set) var min: Double = .nan 16 | private(set) var max: Double = .nan 17 | private(set) var mean: Double = .nan 18 | private var m2: Double = .nan 19 | private(set) var lastValue: Double = .nan 20 | 21 | var variance: Double { return count <= 1 ? 0 : m2/(count - 1) } 22 | 23 | var stddev: Double { return sqrt(variance) } 24 | 25 | var stats: Stats { 26 | return Stats(count: Int(count), min: min, max: max, mean: mean, stddev: stddev) 27 | } 28 | 29 | mutating func addMeasurement(_ value: Double) { 30 | guard count != 0 31 | else { 32 | reset(firstValue: value) 33 | return 34 | } 35 | // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_Online_algorithm 36 | count += 1 37 | min = Swift.min(min, value) 38 | max = Swift.max(max, value) 39 | let d1 = value - mean 40 | mean += d1/count 41 | let d2 = value - mean 42 | m2 += d1*d2 43 | lastValue = value 44 | } 45 | 46 | mutating func reset(firstValue: Double? = nil) { 47 | if let firstValue = firstValue { 48 | count = 1 49 | min = firstValue 50 | max = firstValue 51 | mean = firstValue 52 | m2 = 0 53 | lastValue = firstValue 54 | } else { 55 | count = 0 56 | min = .nan 57 | max = .nan 58 | mean = .nan 59 | m2 = .nan 60 | lastValue = .nan 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Demo/Utils/StringExtension.swift: -------------------------------------------------------------------------------- 1 | extension String.Index { 2 | /// Temporary compatibility shim for Xcode < 10.2. 3 | func _utf16Offset(in string: String) -> Int { 4 | #if swift(>=4.2.5) // This version number is a guess. 5 | return utf16Offset(in: string) 6 | #else 7 | return string.utf16.distance(from: string.utf16.startIndex, to: self) 8 | #endif 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Demo/Utils/UIColorExtension.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | extension UIColor { 6 | public convenience init(rgb: Int, alpha: CGFloat = 1) { 7 | precondition(0 <= rgb && rgb <= 0xFF_FF_FF) 8 | precondition(0 <= alpha && alpha <= 1) 9 | let red = rgb >> 16 10 | let green = (rgb >> 8) & 0xFF 11 | let blue = rgb & 0xFF 12 | self.init(red: CGFloat(red)/255, green: CGFloat(green)/255, blue: CGFloat(blue)/255, 13 | alpha: alpha) 14 | } 15 | 16 | struct RGBA { 17 | var red: CGFloat 18 | var green: CGFloat 19 | var blue: CGFloat 20 | var alpha: CGFloat 21 | } 22 | 23 | var rgba: RGBA { 24 | var result = RGBA(red: 0, green: 0, blue: 0, alpha: 1) 25 | getRed(&result.red, green: &result.green, blue: &result.blue, alpha: &result.alpha) 26 | return result 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Demo/Utils/UIEdgeInsetsExtension.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | extension UIEdgeInsets { 6 | init(uniformInset: CGFloat) { 7 | self.init(top: uniformInset, left: uniformInset, bottom: uniformInset, right: uniformInset) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Demo/Utils/UIViewExtension.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import UIKit 4 | 5 | extension UIView { 6 | /// Returns the first `UIViewController` in the view's responder chain, or `nil` if there's none. 7 | var stu_viewController: UIViewController? { 8 | var r: UIResponder = self 9 | while let next = r.next { 10 | if let vc = next as? UIViewController { 11 | return vc 12 | } 13 | r = next 14 | } 15 | return nil 16 | } 17 | 18 | func convertBounds(of view: UIView) -> CGRect { 19 | return self.convert(view.bounds, from: view) 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016-2018, Stephan Tolksdorf. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The STULabel library incorporates data derived from the Unicode Character 26 | Database, Copyright (c) 1991‒2018 Unicode, Inc., which is distributed under the 27 | license available at: 28 | http://www.unicode.org/copyright.html#License 29 | -------------------------------------------------------------------------------- /STULabel.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /STULabel.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /STULabel.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Latest 7 | 8 | 9 | -------------------------------------------------------------------------------- /STULabel/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /STULabel/Internal/AtomicEnum.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "Common.hpp" 4 | 5 | #include 6 | 7 | namespace stu_label { 8 | 9 | template 10 | struct AtomicEnum { 11 | static_assert(isEnum); 12 | using Value = UnderlyingType; 13 | 14 | std::atomic value; 15 | 16 | explicit AtomicEnum(Enum value) noexcept 17 | : value{static_cast(value)} {} 18 | 19 | STU_INLINE 20 | Enum load(std::memory_order mo) const { 21 | return static_cast(value.load(mo)); 22 | } 23 | 24 | STU_INLINE 25 | void store(Enum e, std::memory_order mo) { 26 | return value.store(static_cast(e), mo); 27 | } 28 | 29 | STU_INLINE 30 | Enum fetch_or(Enum e, std::memory_order mo) { 31 | return static_cast(value.fetch_or(static_cast(e), mo)); 32 | } 33 | 34 | STU_INLINE 35 | Enum fetch_and(Enum e, std::memory_order mo) { 36 | return static_cast(value.fetch_and(static_cast(e), mo)); 37 | } 38 | }; 39 | 40 | } // namespace stu_label 41 | -------------------------------------------------------------------------------- /STULabel/Internal/CancellationFlag.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUCancellationFlag.h" 4 | 5 | #import "Common.hpp" 6 | 7 | #include 8 | 9 | namespace stu_label { 10 | 11 | STU_INLINE_T 12 | bool isCancelled(const STUCancellationFlag& flag) { 13 | return STUCancellationFlagGetValue(&flag); 14 | } 15 | 16 | struct CancellationFlag : STUCancellationFlag { 17 | static const CancellationFlag neverCancelledFlag; 18 | 19 | STU_CONSTEXPR_T 20 | CancellationFlag() : STUCancellationFlag{} {} 21 | 22 | explicit STU_INLINE_T 23 | operator bool() const { return STUCancellationFlagGetValue(this); } 24 | 25 | void setCancelled() { return STUCancellationFlagSetCancelled(this); } 26 | 27 | void clear() { 28 | atomic_store_explicit(&isCancelled, false, memory_order_relaxed); 29 | } 30 | 31 | }; 32 | 33 | } // namespace stu_label 34 | -------------------------------------------------------------------------------- /STULabel/Internal/CancellationFlag.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "CancellationFlag.hpp" 4 | 5 | namespace stu_label { 6 | 7 | const CancellationFlag CancellationFlag::neverCancelledFlag{}; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /STULabel/Internal/Color-no-ARC.mm: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2017–2018 Stephan Tolksdorf 3 | 4 | #if __has_feature(objc_arc) 5 | #error This file must be compiled with -fno-objc-arc 6 | #endif 7 | 8 | #import "STULabel/STUDefines.h" 9 | 10 | #import 11 | 12 | namespace stu_label { 13 | 14 | // We don't want to include the header since this is a no-objc-arc file. 15 | STU_DISABLE_CLANG_WARNING("-Wmissing-prototypes") 16 | 17 | CGColor* cgColor(UIColor* color) { 18 | return color.CGColor; 19 | } 20 | 21 | STU_REENABLE_CLANG_WARNING 22 | 23 | } // namespace stu_label 24 | -------------------------------------------------------------------------------- /STULabel/Internal/Color.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "Color.hpp" 4 | 5 | namespace stu_label { 6 | 7 | ColorFlags colorFlags(const RGBA& rgba) { 8 | const auto [r, g, b, a] = rgba; 9 | if (a <= 0) return ColorFlags::isClear; 10 | return (a < 1 ? ColorFlags{} : ColorFlags::isOpaque) 11 | | (r == g && g == b ? ColorFlags{} : ColorFlags::isNotGray) 12 | | (0 <= r && r <= 1 && 0 <= g && g <= 1 && 0 <= b && b <= 1 13 | ? ColorFlags{} : ColorFlags::isExtended) 14 | | (r == 0 && g == 0 && b == 0 && a >= 1 ? ColorFlags::isBlack : ColorFlags{}); 15 | } 16 | 17 | ColorFlags colorFlags(UIColor* __unsafe_unretained __nullable color) { 18 | if (STU_UNLIKELY(!color)) { 19 | return ColorFlags::isClear; 20 | } 21 | if (Optional rgba = RGBA::of(color)) { 22 | return colorFlags(*rgba); 23 | } 24 | return ColorFlags::isNotGray; 25 | } 26 | 27 | ColorFlags colorFlags(CGColor* __nullable color) { 28 | if (STU_UNLIKELY(!color)) { 29 | return ColorFlags::isClear; 30 | } 31 | // Allocating a temporary UIColor object here is inefficient, but convenient. 32 | return colorFlags([UIColor colorWithCGColor:color]); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /STULabel/Internal/Common.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #if !__has_feature(objc_arc) 4 | #error This header must only be included from files compiled with ARC support enabled 5 | #endif 6 | 7 | // We can't call this header "Config.hpp" due to https://github.com/CocoaPods/CocoaPods/issues/7807 8 | 9 | #if defined(NDEBUG) 10 | #error NDEBUG is defined. Do you really want to disable all runtime bounds checking in STULabel? 11 | #endif 12 | 13 | #import "stu/ArrayRef.hpp" 14 | #import "stu/NSFoundationSupport.hpp" 15 | #import "stu/Optional.hpp" 16 | #import "stu/OptionsEnum.hpp" 17 | 18 | #import 19 | #import 20 | #import 21 | #import 22 | 23 | namespace stu_label { 24 | using namespace stu; 25 | // These using declarations are necessary due to identically named global typedefs in MacTypes.h 26 | using stu::Int8; 27 | using stu::UInt8; 28 | using stu::Int16; 29 | using stu::UInt16; 30 | using stu::Int32; 31 | using stu::UInt32; 32 | using stu::Int64; 33 | using stu::UInt64; 34 | using stu::Float32; 35 | using stu::Float64; 36 | using stu::Fixed; 37 | } 38 | -------------------------------------------------------------------------------- /STULabel/Internal/CoreAnimationUtils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUImageUtils.h" 4 | 5 | #import "Common.hpp" 6 | 7 | #import 8 | 9 | #import 10 | 11 | namespace stu_label { 12 | 13 | STU_INLINE bool is_main_thread() { return pthread_main_np(); } 14 | 15 | STU_INLINE bool inUIViewAnimation() { return [UIView inheritedAnimationDuration] > 0; } 16 | 17 | UIWindow* window(CALayer* layer); 18 | 19 | API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) 20 | STUPredefinedCGImageFormat contentsImageFormat(NSString* caLayerContentsFormat, 21 | STUPredefinedCGImageFormat fallbackFormat); 22 | 23 | API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) 24 | void setContentsImageFormat(CALayer* layer, STUPredefinedCGImageFormat format); 25 | 26 | } // namespace stu_label 27 | -------------------------------------------------------------------------------- /STULabel/Internal/CoreGraphicsUtils.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "CoreGraphicsUtils.hpp" 4 | 5 | #import "Rect.hpp" 6 | 7 | namespace stu_label { 8 | 9 | void addReversedRectPath(CGPath& path, const CGAffineTransform* __nullable transform, CGRect cgRect) { 10 | const Rect rect = cgRect; 11 | CGPathMoveToPoint(&path, transform, rect.x.start, rect.y.start); 12 | CGPathAddLineToPoint(&path, transform, rect.x.start, rect.y.end); 13 | CGPathAddLineToPoint(&path, transform, rect.x.end, rect.y.end); 14 | CGPathAddLineToPoint(&path, transform, rect.x.end, rect.y.start); 15 | CGPathCloseSubpath(&path); 16 | } 17 | 18 | } // namespace stu_label 19 | 20 | -------------------------------------------------------------------------------- /STULabel/Internal/DefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Stephan Tolksdorf 2 | 3 | // See https://github.com/stephan-tolksdorf/STULabel/issues/5 4 | #if TARGET_OS_MACCATALYST 5 | #define UInt ::stu::UInt 6 | #endif 7 | 8 | -------------------------------------------------------------------------------- /STULabel/Internal/DrawingContext.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "DrawingContext.hpp" 4 | 5 | #include "DefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h" 6 | 7 | namespace stu_label { 8 | 9 | constexpr UInt16 colorIndexOffsets[2] = {ColorIndex::fixedColorIndexRange.start, 10 | ColorIndex::fixedColorIndexRange.end}; 11 | 12 | STU_NO_INLINE 13 | CGColor* DrawingContext::cgColor(ColorIndex colorIndex) { 14 | const UInt isTextFrameColor = colorIndex.value >= ColorIndex::fixedColorIndexRange.end; 15 | UInt32 index = colorIndex.value; 16 | index -= colorIndexOffsets[isTextFrameColor]; // May wrap around. 17 | STU_ASSERT(index < colorCounts_[isTextFrameColor]); 18 | return colorArrays_[isTextFrameColor][index].cgColor(); 19 | } 20 | 21 | STU_NO_INLINE 22 | void DrawingContext::setShadow_slowPath(const TextStyle::ShadowInfo* __nullable shadowInfo) { 23 | const TextStyle::ShadowInfo* const previousShadowInfo = shadowInfo_; 24 | shadowInfo_ = shadowInfo; 25 | if (shadowInfo) { 26 | if (shadowInfo == previousShadowInfo 27 | || (shadowInfo && previousShadowInfo && *shadowInfo == *previousShadowInfo)) 28 | { 29 | return; 30 | } 31 | const CGFloat yScale = shadowYExtraScaleFactor_; 32 | const CGFloat xScale = abs(yScale); 33 | const CGSize offset = {xScale*(shadowInfo->offsetX + currentShadowExtraXOffset()), 34 | yScale*shadowInfo->offsetY}; 35 | const CGFloat blurRadius = xScale*shadowInfo->blurRadius; 36 | CGContextSetShadowWithColor(cgContext_, offset, blurRadius, cgColor(shadowInfo->colorIndex)); 37 | } else { 38 | CGContextSetShadowWithColor(cgContext_, (CGSize){}, 0, nil); 39 | } 40 | } 41 | 42 | STU_NO_INLINE 43 | void DrawingContext::initializeGlyphBoundsCache() { 44 | STU_APPEARS_UNUSED 45 | const bool isNotInitialized = !glyphBoundsCache_; 46 | STU_ASSUME(isNotInitialized); 47 | glyphBoundsCache_.emplace(); 48 | } 49 | 50 | } // namespace stu_label 51 | -------------------------------------------------------------------------------- /STULabel/Internal/GlyphPathIntersectionBounds.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "Common.hpp" 4 | 5 | namespace stu_label { 6 | 7 | struct LowerAndUpperInterval { 8 | Range lower; 9 | Range upper; 10 | }; 11 | 12 | /// @brief Finds the x-axis bounds of the intersection of a path with one or two horizontal lines. 13 | /// 14 | /// The implementation is optimized for a single line or two lines close to each other, like e.g. 15 | /// text underlines. 16 | /// 17 | /// @param lowerLineY The y interval for the lower horizontal line. 18 | /// @param upperLineY 19 | /// The y interval for the upper horizontal line. 20 | /// If this interval has the same min value as lowerLineY, it is ignored and the returned upper 21 | /// interval will always be empty. 22 | /// @param maxError 23 | /// The desired maximum absolute error of the endpoints of the returned intervals. 24 | /// Must be greater than 0. 25 | /// 26 | /// @pre lowerLineY.min <= upperLineY.min && lowerLineY.max <= uppeLineY.max 27 | LowerAndUpperInterval findXBoundsOfPathIntersectionWithHorizontalLines( 28 | __nonnull CGPathRef path, 29 | Range lowerLineY, Range upperLineY, 30 | CGFloat maxError); 31 | 32 | } // namespace stu_label 33 | -------------------------------------------------------------------------------- /STULabel/Internal/HashTable.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "HashTable.hpp" 4 | 5 | namespace stu_label { 6 | 7 | template class HashTable; 8 | template class HashTable; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /STULabel/Internal/IntervalSearchTable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "Common.hpp" 4 | 5 | #include "DefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h" 6 | 7 | namespace stu_label { 8 | 9 | class IntervalSearchTable { 10 | const Float32* values_; 11 | Int count_; 12 | public: 13 | static constexpr UInt arrayElementSize = 2*sizeof(Float32); 14 | 15 | STU_CONSTEXPR 16 | static UInt sizeInBytesForCount(Int count) { return arrayElementSize*sign_cast(count); }; 17 | 18 | /// `increasingStartValues` and `increasingEndValues` must contain the (non-strictly) 19 | /// monotonically increasing start and end value of the intervals to search. 20 | /// 21 | /// \pre 22 | /// `increasingEndValues.end() == increasingStartValues.start()`, 23 | /// `increasingEndValues.count() == increasingStartValues.count()` 24 | STU_INLINE 25 | IntervalSearchTable(ArrayRef increasingEndValues, 26 | ArrayRef increasingStartValues) 27 | 28 | : values_{increasingEndValues.begin()}, 29 | count_{increasingEndValues.count()} 30 | { 31 | STU_PRECONDITION(increasingEndValues.end() == increasingStartValues.begin()); 32 | STU_PRECONDITION(increasingEndValues.count() == increasingStartValues.count()); 33 | discard(increasingStartValues); 34 | } 35 | 36 | ArrayRef endValues() const { 37 | return {values_, count_, unchecked}; 38 | } 39 | 40 | ArrayRef startValues() const { 41 | return {values_ + count_, count_, unchecked}; 42 | }; 43 | 44 | 45 | Range indexRange(Range yRange) const; 46 | }; 47 | 48 | 49 | } // namespace stu_label 50 | 51 | #include "UndefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h" 52 | -------------------------------------------------------------------------------- /STULabel/Internal/IntervalSearchTable.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "IntervalSearchTable.hpp" 4 | 5 | #import "stu/BinarySearch.hpp" 6 | 7 | namespace stu_label { 8 | 9 | Range IntervalSearchTable::indexRange(Range yRange) const { 10 | const Int start = binarySearchFirstIndexWhere( 11 | endValues(), [&](Float32 e) { return e >= yRange.start; }).indexOrArrayCount; 12 | const Int end = binarySearchFirstIndexWhere( 13 | startValues(), [&](Float32 s) { return s > yRange.end; }).indexOrArrayCount; 14 | return {start, end}; 15 | } 16 | 17 | } // stu_label 18 | -------------------------------------------------------------------------------- /STULabel/Internal/LabelRendering.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUTextFrame-Unsafe.h" 4 | 5 | #import "STULabel/STUImageUtils.h" 6 | 7 | #import "STULabel/STULabelDrawingBlock.h" 8 | #import "STULabel/STULabelLayoutInfo-Internal.hpp" 9 | 10 | 11 | #import "PurgeableImage.hpp" 12 | 13 | namespace stu_label { 14 | 15 | enum class LabelRenderMode : UInt8 { 16 | drawInCAContext, 17 | image, 18 | imageInSublayer, 19 | tiledSublayer 20 | }; 21 | constexpr int LabelRenderModeBitSize = 2; 22 | 23 | struct LabelTextFrameRenderInfo { 24 | CGRect bounds; 25 | LabelRenderMode mode; 26 | STUPredefinedCGImageFormat imageFormat; 27 | bool shouldDrawBackgroundColor; 28 | bool isOpaque; 29 | bool mayBeClipped; 30 | }; 31 | 32 | LabelTextFrameRenderInfo labelTextFrameRenderInfo(const STUTextFrame*, 33 | const LabelTextFrameInfo&, 34 | const CGPoint&, 35 | const LabelParameters&, 36 | bool allowExtendedRGBBitmapFormat, 37 | bool preferImageMode, 38 | const STUCancellationFlag* __nullable); 39 | 40 | void drawLabelTextFrame( 41 | const STUTextFrame* textFrame, STUTextFrameRange range, CGPoint origin, 42 | __nullable CGContextRef context, ContextBaseCTM_d, PixelAlignBaselines, 43 | const STUTextFrameDrawingOptions* __nullable, 44 | __nullable STULabelDrawingBlock, const STUCancellationFlag* __nullable); 45 | 46 | PurgeableImage createLabelTextFrameImage(const STUTextFrame*, 47 | const LabelTextFrameRenderInfo&, 48 | const LabelParameters&, 49 | const STUCancellationFlag* __nullable); 50 | 51 | } // namespace stu_label 52 | 53 | 54 | -------------------------------------------------------------------------------- /STULabel/Internal/LineTruncation.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUTextFrame-Unsafe.h" 4 | 5 | #import "Kerning.hpp" 6 | #import "NSAttributedStringRef.hpp" 7 | 8 | namespace stu_label { 9 | 10 | struct TruncatableTextLine { 11 | const NSAttributedStringRef& attributedString; 12 | Range stringRange; 13 | NSArrayRef runs; 14 | Float64 width; 15 | bool isRightToLeftLine; 16 | Range truncatableStringRange; 17 | }; 18 | 19 | #if STU_TRUNCATION_TOKEN_KERNING 20 | struct TokenForKerningPurposes { 21 | NSArrayRef runs; 22 | Float64 width; 23 | NSAttributedStringRef attributedString; 24 | }; 25 | #endif 26 | 27 | struct ExcisedGlyphRange { 28 | Range stringRange; 29 | RunGlyphIndex start; 30 | RunGlyphIndex end; 31 | Float64 adjustedWidthLeftOfExcision; 32 | Float64 adjustedWidthRightOfExcision; 33 | }; 34 | 35 | 36 | /// @note 37 | /// The implementation treats any trailing whitespace as regular text. 38 | /// (Which means that you'll likely have to adapt the implementation if you need to truncate 39 | /// CTLine instances that may contain trailing whitespace.) 40 | /// 41 | /// @pre line.width > maxWidth 42 | /// @pre line.truncationRange ⊆ line.stringRange 43 | /// @pre line.truncationRange == line.stringRange || line.truncationType != kCTLineTruncationMiddle 44 | ExcisedGlyphRange findRangeToExciseForTruncation( 45 | const TruncatableTextLine& line, 46 | CTLineTruncationType truncationType, Float64 maxWidth, 47 | __nullable STUTruncationRangeAdjuster truncationRangeAdjuster 48 | #if STU_TRUNCATION_TOKEN_KERNING 49 | , const TokenForKerningPurposes& tokenRuns 50 | #endif 51 | ); 52 | 53 | } // namespace stu_label 54 | -------------------------------------------------------------------------------- /STULabel/Internal/Localized.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "Common.hpp" 4 | 5 | namespace stu_label { 6 | 7 | NSString* localizationLanguage(); 8 | 9 | NSString* systemLocalizationLanguage(); 10 | 11 | NSString* localized(NSString* key); 12 | 13 | NSString* localizedForSystemLocale(NSString* key); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /STULabel/Internal/NSArrayRef-no-ARC.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #if __has_feature(objc_arc) 4 | #error This file must be compiled with -fno-objc-arc 5 | #endif 6 | 7 | #import "STULabel/STUDefines.h" 8 | 9 | #import 10 | 11 | namespace stu_label::detail { 12 | 13 | // We don't want to include the header since this is a no-objc-arc file. 14 | STU_DISABLE_CLANG_WARNING("-Wmissing-prototypes") 15 | 16 | CFTypeRef objectAtIndex(NSArray* array, id (* method)(NSArray *, SEL, NSUInteger), 17 | NSUInteger index) 18 | { 19 | return method(array, @selector(objectAtIndex:), index); 20 | } 21 | 22 | STU_REENABLE_CLANG_WARNING 23 | 24 | } 25 | -------------------------------------------------------------------------------- /STULabel/Internal/NSAttributedString-no-ARC.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #if __has_feature(objc_arc) 4 | #error This file must be compiled with -fno-objc-arc 5 | #endif 6 | 7 | #import "STULabel/STUDefines.h" 8 | 9 | #import 10 | 11 | namespace stu_label::detail { 12 | 13 | // We don't want to include the header since this is a no-objc-arc file. 14 | STU_DISABLE_CLANG_WARNING("-Wmissing-prototypes") 15 | 16 | CFStringRef getStringWithoutRetain(NSAttributedString* attributedString) { 17 | return (CFStringRef)[attributedString string]; 18 | } 19 | 20 | STU_REENABLE_CLANG_WARNING 21 | 22 | } 23 | -------------------------------------------------------------------------------- /STULabel/Internal/Once.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "stu/TypeTraits.hpp" 4 | 5 | #import 6 | 7 | #if !DISPATCH_ONCE_INLINE_FASTPATH 8 | #error This implementation depends on the libdispatch fast path. 9 | #endif 10 | 11 | namespace stu_label { 12 | /// Must only be used as a zero-initialized static/global. 13 | struct Once { 14 | dispatch_once_t once; 15 | 16 | STU_INLINE_T 17 | bool isInitialized() { 18 | static_assert(stu::isSame); 19 | if (DISPATCH_EXPECT(this->once, ~0L) == ~0L) { 20 | dispatch_compiler_barrier(); 21 | DISPATCH_COMPILER_CAN_ASSUME(this->once == ~0L); 22 | return true; 23 | } 24 | return false; 25 | } 26 | 27 | STU_INLINE 28 | void initialize(void* __nullable context, dispatch_function_t function) { 29 | #pragma push_macro("dispatch_once_f") 30 | #undef dispatch_once_f 31 | dispatch_once_f(&this->once, context, function); 32 | #pragma pop_macro("dispatch_once_f") 33 | DISPATCH_COMPILER_CAN_ASSUME(this->once == ~0L); 34 | } 35 | }; 36 | } 37 | 38 | #define STU_STATIC_CONST_ONCE_WITH_INVOKE_ATTRIBUTE(Type, name, invokeAttribute, initializer) \ 39 | static ::stu_label::Once name##_once; \ 40 | static Type name##_value; \ 41 | struct name##_initializer { \ 42 | static STU_NO_INLINE invokeAttribute void invoke() { name##_once.initialize(nullptr, body); } \ 43 | private: \ 44 | static void body(void*) { name##_value = initializer; } \ 45 | }; \ 46 | if (!name##_once.isInitialized()) { \ 47 | name##_initializer::invoke(); \ 48 | } \ 49 | Type const& name = name##_value 50 | 51 | #define STU_STATIC_CONST_ONCE(Type, name, initializer) \ 52 | STU_STATIC_CONST_ONCE_WITH_INVOKE_ATTRIBUTE(Type, name, , initializer) 53 | 54 | #define STU_STATIC_CONST_ONCE_PRESERVE_MOST(Type, name, initializer) \ 55 | STU_STATIC_CONST_ONCE_WITH_INVOKE_ATTRIBUTE(Type, name, STU_PRESERVE_MOST, initializer) 56 | 57 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelAddToContactsViewController.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | #import 6 | 7 | @interface STULabelAddToContactsViewController : UINavigationController 8 | - (instancetype)initWithContact:(CNContact *)contact NS_DESIGNATED_INITIALIZER; 9 | 10 | 11 | - (instancetype)initWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass NS_UNAVAILABLE; 12 | 13 | - (instancetype)initWithRootViewController:(UIViewController *)rootViewController NS_UNAVAILABLE; 14 | 15 | - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE; 16 | 17 | - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelGhostingMaskLayer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STULayerWithNullDefaultActions.h" 4 | #import "STULabel/STUTextLink.h" 5 | 6 | NS_ASSUME_NONNULL_BEGIN 7 | 8 | @interface STULabelGhostingMaskLayer : STUShapeLayerWithNullDefaultActions 9 | 10 | - (void)setMaskedLayerFrame:(CGRect)maskedLayerFrame links:(STUTextLinkArray *)links; 11 | 12 | - (bool)hasGhostedLink:(STUTextLink *)link; 13 | 14 | - (void)ghostLink:(STUTextLink *)link; 15 | 16 | /// Returns true if this was the last ghosted link. 17 | - (bool)unghostLink:(STUTextLink *)link; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelLinkOverlayLayer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STULabel/STULabelOverlayStyle.h" 4 | #import "STULabel/STULayerWithNullDefaultActions.h" 5 | #import "STULabel/STUTextLink.h" 6 | 7 | /// The bounds are always CGRectZero, but the shape extends beyond the bounds. 8 | @interface STULabelLinkOverlayLayer : STUShapeLayerWithNullDefaultActions 9 | 10 | /// The layer's initial `hidden` value is false. 11 | - (null_unspecified instancetype)initWithStyle:(nonnull STULabelOverlayStyle*)style 12 | link:(nonnull STUTextLink *)link 13 | NS_DESIGNATED_INITIALIZER; 14 | 15 | @property (nonatomic, strong, nonnull) STUTextLink *link; 16 | 17 | @property (nonatomic, strong, nonnull) STULabelOverlayStyle *overlayStyle; 18 | 19 | - (void)setHidden:(BOOL)hidden; 20 | 21 | - (void)setHidden:(BOOL)hidden 22 | withAnimationCompletion:(void ( ^ __nullable)(STULabelLinkOverlayLayer * __nonnull))completion; 23 | 24 | @end 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelSubrangeView.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STULabel.h" 4 | 5 | #import "STULabelTiledLayer.h" 6 | 7 | typedef void (^ STULabelSubrangeDrawingBlock)(CGContextRef, CGRect, 8 | const STUCancellationFlag * __nullable); 9 | 10 | @interface STULabelSubrangeView : UIView 11 | @property (nonatomic, nullable) STULabelSubrangeDrawingBlock drawingBlock; 12 | @end 13 | 14 | @interface STULabelTiledSubrangeView : STULabelSubrangeView 15 | @end 16 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelSubrangeView.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabelSubrangeView.h" 4 | 5 | #import "LabelRendering.hpp" 6 | 7 | using namespace stu; 8 | using namespace stu_label; 9 | 10 | @implementation STULabelSubrangeView 11 | 12 | - (instancetype)init { 13 | self = [super init]; 14 | self.opaque = false; 15 | return self; 16 | } 17 | 18 | - (void)drawRect:(CGRect)rect { 19 | if (_drawingBlock) { 20 | _drawingBlock(UIGraphicsGetCurrentContext(), rect, nullptr); 21 | } 22 | } 23 | 24 | - (void)setContentScaleFactor:(CGFloat)contentScaleFactor { 25 | // When the view of a UITargetedDragPreview instance is inserted into the view hierarchy, its 26 | // contentScaleFactor is reset to the screen's scale. Since we don't do the insertion ourselves 27 | // and we don't want the view to appear pixelated when when it's the subview of a zoomed-in label, 28 | // we clamp the scale here. 29 | [super setContentScaleFactor:max(contentScaleFactor, self.superview.contentScaleFactor)]; 30 | } 31 | 32 | @end 33 | 34 | @implementation STULabelTiledSubrangeView 35 | 36 | + (Class)layerClass { 37 | return STULabelTiledLayer.class; 38 | } 39 | 40 | - (void)setDrawingBlock:(STULabelSubrangeDrawingBlock)drawingBlock { 41 | [super setDrawingBlock:drawingBlock]; 42 | [((STULabelTiledLayer*)self.layer) setDrawingBlock: drawingBlock]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /STULabel/Internal/STULabelTiledLayer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUCancellationFlag.h" 4 | #import "STULabel/STUImageUtils.h" 5 | #import "STULabel/STULayerWithNullDefaultActions.h" 6 | 7 | STU_ASSUME_NONNULL_AND_STRONG_BEGIN 8 | 9 | typedef void (^ STULabelTileDrawingBlock)(CGContextRef context, CGRect rect, 10 | const STUCancellationFlag *cancellationFlag); 11 | 12 | /// Displays synchronously, prerenders asynchronously and uses larger tile sizes than CATiledLayer. 13 | @interface STULabelTiledLayer : STULayerWithNullDefaultActions 14 | 15 | @property (nonatomic, nullable) STULabelTileDrawingBlock drawingBlock; 16 | 17 | @property (nonatomic) STUPredefinedCGImageFormat imageFormat; 18 | 19 | @end 20 | 21 | STU_ASSUME_NONNULL_AND_STRONG_END 22 | -------------------------------------------------------------------------------- /STULabel/Internal/STUMediaTimingFunctionUtils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUDefines.h" 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | typedef struct { 10 | Float32 c1x, c1y, c2x, c2y; 11 | } STUMediaTimingFunctionControlPoints; 12 | 13 | STU_INLINE 14 | STUMediaTimingFunctionControlPoints stuMediaTimingFunctionControlPoints(CAMediaTimingFunction *f) { 15 | Float32 c1[2]; 16 | [f getControlPointAtIndex:1 values:c1]; 17 | Float32 c2[2]; 18 | [f getControlPointAtIndex:2 values:c2]; 19 | return (STUMediaTimingFunctionControlPoints){c1[0], c1[1], c2[0], c2[1]}; 20 | } 21 | 22 | STU_INLINE bool stu_CAMediaTimingFunctionEqualToFunction( 23 | CAMediaTimingFunction * __nullable a, CAMediaTimingFunction * __nullable b) 24 | { 25 | if (a == b) return true; 26 | if (!a || !b) return false; 27 | const STUMediaTimingFunctionControlPoints cas = stuMediaTimingFunctionControlPoints(a); 28 | const STUMediaTimingFunctionControlPoints cbs = stuMediaTimingFunctionControlPoints(b); 29 | return cas.c1x == cbs.c1x && cas.c1y == cbs.c1y 30 | && cas.c2x == cbs.c2x && cas.c2y == cbs.c2y; 31 | } 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /STULabel/Internal/STUPlaceholderObjects.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUShapedString.h" 4 | #import "STULabel/STUTextFrame.h" 5 | 6 | @interface STUUninitializedShapedString : STUShapedString @end 7 | 8 | @interface STUUninitializedTextFrame : STUTextFrame @end 9 | 10 | -------------------------------------------------------------------------------- /STULabel/Internal/SortedIntervalBuffer.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "SortedIntervalBuffer.hpp" 4 | 5 | namespace stu_label { 6 | 7 | template class SortedIntervalBuffer; 8 | 9 | } // stu_label 10 | -------------------------------------------------------------------------------- /STULabel/Internal/StyledStringRangeIteration.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "TextStyle.hpp" 4 | 5 | #import "stu/FunctionRef.hpp" 6 | 7 | namespace stu_label { 8 | 9 | struct TextFrame; 10 | struct TextFrameParagraph; 11 | 12 | struct ShouldStop { 13 | bool value; 14 | 15 | STU_CONSTEXPR ShouldStop() : value{false} {} 16 | STU_CONSTEXPR explicit ShouldStop(bool value) : value{value} {} 17 | 18 | STU_CONSTEXPR explicit operator bool() const { return value; } 19 | STU_CONSTEXPR bool operator==(ShouldStop other) { return value == other.value; } 20 | STU_CONSTEXPR bool operator!=(ShouldStop other) { return !(*this == other); } 21 | }; 22 | constexpr ShouldStop stop = ShouldStop{true}; 23 | 24 | struct StyledStringRange { 25 | Range stringRange; 26 | int32_t offsetInTruncatedString; 27 | bool isTruncationTokenRange; 28 | }; 29 | 30 | namespace detail { 31 | 32 | ShouldStop forEachStyledStringRange( 33 | const TextFrame& textFrame, 34 | const TextFrameParagraph& paragraph, Range lineIndexRange, 35 | Optional styleOverride, 36 | FunctionRef body); 37 | } 38 | 39 | } // namespace stu_label 40 | -------------------------------------------------------------------------------- /STULabel/Internal/TextFlags.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STULabel/STUTextFrame.h" 4 | 5 | #import "Common.hpp" 6 | 7 | namespace stu_label { 8 | 9 | enum class TextFlags : UnderlyingType { 10 | hasLink = STUTextHasLink, 11 | hasBackground = STUTextHasBackground, 12 | hasShadow = STUTextHasShadow, 13 | hasUnderline = STUTextHasUnderline, 14 | hasStrikethrough = STUTextHasStrikethrough, 15 | hasStroke = STUTextHasStroke, 16 | hasAttachment = STUTextHasAttachment, 17 | hasBaselineOffset = STUTextHasBaselineOffset, 18 | mayNotBeGrayscale = STUTextMayNotBeGrayscale, 19 | usesExtendedColor = STUTextUsesExtendedColor, 20 | 21 | decorationFlags = STUTextDecorationFlags, 22 | colorFlags = STUTextMayNotBeGrayscale | STUTextUsesExtendedColor, 23 | }; 24 | static constexpr int TextFlagsBitSize = STUTextFlagsBitSize; 25 | static_assert((1 << TextFlagsBitSize) > ( STUTextDecorationFlags 26 | | STUTextHasAttachment 27 | | STUTextHasBaselineOffset 28 | | STUTextMayNotBeGrayscale 29 | | STUTextUsesExtendedColor)); 30 | 31 | STU_CONSTEXPR STUTextFlags stuTextFlags(TextFlags flags) { 32 | return static_cast(flags); 33 | } 34 | 35 | } // namespace stu_label 36 | 37 | template <> 38 | struct stu::IsOptionsEnum : stu::True {}; 39 | 40 | namespace stu_label::detail { 41 | static_assert(STUTextFlagsBitSize < sizeof(TextFlags)*8); 42 | constexpr TextFlags everyRunFlag = static_cast(1 << STUTextFlagsBitSize); 43 | } 44 | -------------------------------------------------------------------------------- /STULabel/Internal/TextFrameLine-FontMetric.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "TextFrame.hpp" 4 | 5 | namespace stu_label { 6 | 7 | template 8 | STU_INLINE 9 | CGFloat getRunFontMetric(GlyphRunRef run) { 10 | const CTFont* font = run.font(); 11 | if constexpr (metric == FontMetric::xHeight) return [(__bridge UIFont*)font xHeight]; 12 | else if constexpr (metric == FontMetric::capHeight) return [(__bridge UIFont*)font capHeight]; 13 | else static_assert(false && metric == metric); 14 | } 15 | 16 | template 17 | Float32 TextFrameLine::maxFontMetricValue() const { 18 | _Atomic(Float32)* p; 19 | { 20 | TextFrameLine& line = const_cast(*this); 21 | if constexpr (metric == FontMetric::xHeight) { p = &line._xHeight; } 22 | else if constexpr (metric == FontMetric::capHeight) { p = &line._capHeight; } 23 | else static_assert(false && metric == metric); 24 | } 25 | Float32 value = atomic_load_explicit(p, memory_order_relaxed); 26 | if (value == FLT_MAX) { 27 | CGFloat maxValue = 0; 28 | forEachGlyphSpan([&maxValue](TextLinePart, CTLineXOffset, GlyphSpan glyphSpan) { 29 | maxValue = max(maxValue, getRunFontMetric(glyphSpan.run())); 30 | }); 31 | value = narrow_cast(maxValue); 32 | atomic_store_explicit(p, value, memory_order_relaxed); 33 | } 34 | return value; 35 | } 36 | template Float32 TextFrameLine::maxFontMetricValue() const; 37 | template Float32 TextFrameLine::maxFontMetricValue() const; 38 | 39 | } // namespace stu_label 40 | -------------------------------------------------------------------------------- /STULabel/Internal/ThreadLocalAllocator.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "ThreadLocalAllocator.hpp" 4 | 5 | namespace stu_label { 6 | 7 | #if STU_HAS_THREAD_LOCAL 8 | 9 | thread_local ThreadLocalArenaAllocator* ThreadLocalArenaAllocator::instance_pointer; 10 | 11 | #else 12 | 13 | static pthread_key_t createThreadLocalArenaAllocatorPThreadKey() { 14 | pthread_key_t key; 15 | const int RC = pthread_key_create(&key, nullptr); 16 | STU_CHECK(RC == 0); 17 | return key; 18 | } 19 | 20 | const pthread_key_t ThreadLocalArenaAllocator::instance_key = createThreadLocalArenaAllocatorPThreadKey(); 21 | 22 | #endif 23 | 24 | } 25 | -------------------------------------------------------------------------------- /STULabel/Internal/UndefineUIntOnCatalystToWorkAroundGlobalNamespacePollution.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Stephan Tolksdorf 2 | 3 | #if TARGET_OS_MACCATALYST 4 | #undef UInt 5 | #endif 6 | -------------------------------------------------------------------------------- /STULabel/Internal/Unretained.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "stu/Comparable.hpp" 4 | 5 | namespace stu_label { 6 | 7 | /// A simple wrapper for an __unsafe_unretained Objective-C pointer, which is useful for 8 | /// returning unretained pointers from functions in ARC code. 9 | /// (LLVM currently can't optimize away the implicit autoreleases that are triggered when returning 10 | /// an Objective-C pointer from an inline function.) 11 | template 12 | struct Unretained : stu::Comparable> { 13 | static_assert(stu::isPointer); 14 | 15 | Pointer __unsafe_unretained unretained; 16 | 17 | /* implicit */ STU_CONSTEXPR_T 18 | Unretained(Pointer __unsafe_unretained pointer) : unretained(pointer) {} 19 | 20 | explicit STU_CONSTEXPR_T 21 | operator bool() const { return unretained; } 22 | 23 | STU_CONSTEXPR_T 24 | friend bool operator==(Unretained lhs, Unretained rhs) { 25 | return lhs.unretained == rhs.unretained; 26 | } 27 | 28 | STU_CONSTEXPR_T 29 | friend bool operator<(Unretained lhs, Unretained rhs) { 30 | return lhs.unretained < rhs.unretained; 31 | } 32 | }; 33 | 34 | } // namespace stu_label 35 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Allocation.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #include "Allocation.hpp" 4 | 5 | namespace stu::detail { 6 | 7 | [[noreturn]] STU_NO_INLINE 8 | void throwBadAlloc() { 9 | #ifdef __cpp_exceptions 10 | throw std::bad_alloc(); 11 | #else 12 | __builtin_trap(); 13 | #endif 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/ArenaAllocator.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #include "stu/ArenaAllocator.hpp" 4 | 5 | namespace stu { 6 | 7 | template struct detail::VectorBase, false>; 8 | 9 | // template class ArenaAllocator; // clang bug 10 | 11 | } // namespace stu 12 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Assert.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #include "stu/Config.h" 4 | 5 | #undef STU_CHECK_MSG 6 | #undef STU_ASSERT_MAY_THROW 7 | #undef STU_CHECK 8 | #undef STU_ASSERT 9 | #undef STU_DEBUG_ASSERT 10 | #undef STU_PRECONDITION 11 | 12 | #define STU_CHECK_MSG(assertion, message) \ 13 | (STU_LIKELY(assertion) ? (void)0 \ 14 | : stu_assertion_failed(__FILE__, __LINE__, __PRETTY_FUNCTION__, message)) 15 | 16 | #if STU_DEBUG 17 | #define STU_CHECK(assertion) STU_CHECK_MSG(assertion, #assertion) 18 | #define STU_ASSERT_MAY_THROW 1 19 | #else 20 | #define STU_CHECK(assertion) (STU_LIKELY(assertion) ? (void)0 : __builtin_trap()) 21 | #define STU_ASSERT_MAY_THROW 0 22 | #endif 23 | 24 | #if defined(NDEBUG) // Release build without asserts 25 | 26 | #define STU_ASSERT(assertion) STU_ASSUME(assertion) 27 | #define STU_DEBUG_ASSERT(assertion) STU_ASSUME(assertion) 28 | 29 | #elif !STU_DEBUG // Release build with asserts 30 | 31 | #define STU_ASSERT(assertion) STU_CHECK(assertion) 32 | #define STU_DEBUG_ASSERT(assertion) 33 | 34 | #else // Debug build 35 | 36 | #define STU_ASSERT(assertion) STU_CHECK(assertion) 37 | #define STU_DEBUG_ASSERT(assertion) STU_ASSERT(assertion) 38 | 39 | #endif 40 | 41 | #define STU_PRECONDITION(condition) STU_ASSERT(condition) 42 | 43 | #ifdef __cplusplus 44 | extern "C" 45 | #endif 46 | void stu_assertion_failed(const char *fileName, int line, const char *functionName, 47 | const char *condition) 48 | __attribute__((noreturn)); 49 | 50 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Assert.m: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #include "stu/Assert.h" 4 | 5 | #import 6 | 7 | #if STU_DEBUG 8 | #import 9 | #endif 10 | 11 | #if STU_ASSERT_MAY_THROW 12 | _Atomic(bool) stu_assertion_test; 13 | #endif 14 | 15 | #define handleFailure(fileName, line, functionName, format, ...) \ 16 | [[NSAssertionHandler currentHandler] \ 17 | handleFailureInFunction:(functionName ? [NSString stringWithUTF8String:functionName] \ 18 | : @"") \ 19 | file:(fileName ? [NSString stringWithUTF8String:fileName] \ 20 | : @"") \ 21 | lineNumber:line \ 22 | description:format, ##__VA_ARGS__]; 23 | 24 | #ifdef __cplusplus 25 | extern "C" 26 | #endif 27 | __attribute__((noreturn)) 28 | void stu_assertion_failed(const char *fileName, int line, const char *functionName, 29 | const char *condition) 30 | { 31 | #if STU_DEBUG 32 | if (atomic_load_explicit(&stu_assertion_test, memory_order_relaxed)) { 33 | [NSException raise:NSInternalInconsistencyException format:@"Expected assertion failure"]; 34 | } 35 | #endif 36 | handleFailure(fileName, line, functionName, @"Condition not satisfied: %s", condition); 37 | __builtin_trap(); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Casts.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #include "stu/TypeTraits.hpp" 6 | 7 | namespace stu { 8 | 9 | template 10 | STU_CONSTEXPR_T 11 | T bit_cast(const U& value) noexcept { 12 | static_assert(sizeof(T) == sizeof(U)); 13 | T result; 14 | __builtin_memcpy(&result, &value, sizeof(result)); 15 | return result; 16 | } 17 | 18 | template 19 | STU_CONSTEXPR_T 20 | T implicit_cast(EnableIf value) noexcept { 21 | return static_cast(value); // The static_cast is necesary for rvalue references. 22 | } 23 | 24 | 25 | template > = 0> 26 | STU_CONSTEXPR_T 27 | auto sign_cast(Int value) noexcept { 28 | using Result = Conditional, Unsigned, Signed>; 29 | return static_cast(value); 30 | } 31 | 32 | template 33 | STU_CONSTEXPR_T 34 | T narrow_cast(U&& value) noexcept(noexcept(static_cast(value))) { 35 | return static_cast(value); 36 | } 37 | 38 | template && isConvertible> = 0> 40 | STU_CONSTEXPR_T 41 | T down_cast(U* value) noexcept { 42 | return static_cast(value); 43 | } 44 | 45 | template && isConvertible> = 0> 47 | STU_CONSTEXPR_T 48 | T down_cast(U& value) noexcept { 49 | return static_cast(value); 50 | } 51 | 52 | } // namespace stu 53 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Comparable.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #include "stu/TypeTraits.hpp" 6 | 7 | namespace stu { 8 | 9 | template 10 | struct Comparable { 11 | // We need the TT = T indirection to avoid issues with recursive template instantiations. 12 | 13 | template > = 0> 14 | STU_CONSTEXPR 15 | friend bool operator!=(const T& lhs, const T& rhs) noexcept(isNothrowEqualityComparable) { 16 | return !(lhs == rhs); 17 | } 18 | 19 | template > = 0> 20 | STU_CONSTEXPR 21 | friend bool operator>(const T& lhs, const T& rhs) noexcept(isNothrowLessThanComparable) { 22 | return rhs < lhs; 23 | } 24 | 25 | template > = 0> 26 | STU_CONSTEXPR 27 | friend bool operator>=(const T& lhs, const T& rhs) noexcept(isNothrowLessThanComparable) { 28 | return !(lhs < rhs); 29 | } 30 | 31 | template > = 0> 32 | STU_CONSTEXPR 33 | friend bool operator<=(const T& lhs, const T& rhs) noexcept(isNothrowLessThanComparable) { 34 | return !(rhs < lhs); 35 | } 36 | }; 37 | 38 | } // namespace stu 39 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Config.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #if defined(DEBUG) && DEBUG 6 | #define STU_DEBUG 1 7 | #else 8 | #define STU_DEBUG 0 9 | #endif 10 | 11 | #define STU_INLINE inline __attribute__((always_inline)) 12 | 13 | // We'll use 'artificial' here instead of 'nodebug' once clang & LLDB on Mac support it. 14 | #define STU_INLINE_T inline __attribute__((always_inline, nodebug)) 15 | 16 | #define STU_NO_INLINE __attribute__((noinline)) 17 | 18 | #if defined(__x86_64__) || defined(__aarch64__) 19 | #define STU_PRESERVE_MOST __attribute__((preserve_most)) 20 | #else 21 | #define STU_PRESERVE_MOST 22 | #endif 23 | 24 | #define STU_NO_RETURN __attribute__((noreturn)) 25 | 26 | #define STU_NO_THROW __attribute__((nothrow)) 27 | 28 | #define STU_PURE __attribute__((pure)) 29 | 30 | #define STU_APPEARS_UNUSED __attribute__((__unused__)) 31 | 32 | #if STU_DEBUG 33 | #define STU_ASSUME(condition) (void)0 34 | #else 35 | #define STU_ASSUME(condition) __builtin_assume(!!(condition)) 36 | #endif 37 | 38 | #ifdef __clang_analyzer__ 39 | #define STU_ANALYZER_ASSUME(condition) ((condition) ? (void)0 : __builtin_unreachable()) 40 | #else 41 | #define STU_ANALYZER_ASSUME(condition) 42 | #endif 43 | 44 | #define STU_STRINGIZE(x) #x 45 | 46 | #define STU_CONCATENATE(x, y) x##y 47 | 48 | #define STU_DISABLE_CLANG_WARNING(warning_string) \ 49 | _Pragma("clang diagnostic push") \ 50 | _Pragma(STU_STRINGIZE(clang diagnostic ignored warning_string)) 51 | 52 | #define STU_REENABLE_CLANG_WARNING \ 53 | _Pragma("clang diagnostic pop") 54 | 55 | #define STU_DISABLE_LOOP_UNROLL _Pragma("clang loop unroll (disable)") 56 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/InOut.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #include "stu/TypeTraits.hpp" 6 | 7 | namespace stu { 8 | 9 | template 10 | class Out { 11 | static_assert(!isConst); 12 | T& value_; 13 | public: 14 | explicit STU_CONSTEXPR 15 | Out(T& outValueRef) noexcept 16 | : value_(outValueRef) {} 17 | 18 | /* implicit */ STU_CONSTEXPR_T 19 | operator T&() const noexcept { return value_; } 20 | 21 | STU_CONSTEXPR_T 22 | T& get() const noexcept { return value_; } 23 | 24 | template > = 0> 25 | STU_CONSTEXPR 26 | T& operator=(U&& other) const noexcept(isNothrowAssignable) { 27 | value_ = std::forward(other); 28 | return value_; 29 | } 30 | 31 | template ())> 32 | STU_CONSTEXPR_T auto operator*() -> R { return *value_; } 33 | 34 | template ())> 35 | STU_CONSTEXPR_T auto operator->() -> R { return &*value_; } 36 | }; 37 | 38 | template 39 | class InOut { 40 | static_assert(!isConst); 41 | T& value_; 42 | public: 43 | explicit STU_CONSTEXPR_T 44 | InOut(T& inOutValueRef) noexcept : value_(inOutValueRef) {} 45 | 46 | /* implicit */ STU_CONSTEXPR_T 47 | operator T&() const noexcept { return value_; } 48 | 49 | STU_CONSTEXPR_T 50 | T& get() const noexcept { return value_; } 51 | 52 | template > = 0> 53 | STU_CONSTEXPR 54 | T& operator=(U&& other) const noexcept(isNothrowAssignable) { 55 | value_ = std::forward(other); 56 | return value_; 57 | } 58 | 59 | template ())> 60 | STU_CONSTEXPR_T 61 | auto operator*() -> R { return *value_; } 62 | 63 | template ())> 64 | STU_CONSTEXPR_T 65 | auto operator->() -> R { return &*value_; } 66 | }; 67 | 68 | } // namespace stu 69 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Optional.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #include "stu/Optional.hpp" 4 | 5 | #if !STU_NO_EXCEPTIONS 6 | 7 | const char* stu::BadOptionalAccess::what() const noexcept { 8 | return "Attempt to unwrap empty stu::Optional"; 9 | } 10 | 11 | [[noreturn]] STU_NO_INLINE 12 | void stu::detail::throwBadOptionalAccess() { 13 | throw BadOptionalAccess(); 14 | } 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/ScopeGuard.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #include "stu/TypeTraits.hpp" 6 | 7 | namespace stu { 8 | 9 | template 10 | class STU_APPEARS_UNUSED ScopeGuard { 11 | public: 12 | STU_INLINE_T 13 | explicit ScopeGuard(ScopeExitHandler&& handler) 14 | : handler_(std::move(handler)), dismissed_(false) {} 15 | 16 | ScopeGuard(const ScopeGuard&) = delete; 17 | ScopeGuard& operator=(const ScopeGuard&) = delete; 18 | 19 | STU_INLINE 20 | ~ScopeGuard() { 21 | if (!dismissed_) handler_(); 22 | } 23 | 24 | STU_INLINE 25 | void dismiss() { dismissed_ = true; } 26 | 27 | public: 28 | ScopeExitHandler handler_; 29 | bool dismissed_; 30 | }; 31 | 32 | // Dummy implementation for statically disabled scope guards. 33 | template 34 | class STU_APPEARS_UNUSED ScopeGuard { 35 | public: 36 | STU_CONSTEXPR_T 37 | explicit ScopeGuard(ScopeExitHandler&&) {} 38 | 39 | ScopeGuard(const ScopeGuard&) = delete; 40 | ScopeGuard& operator=(const ScopeGuard&) = delete; 41 | 42 | STU_INLINE 43 | constexpr void dismiss() {} 44 | }; 45 | 46 | template 47 | STU_INLINE_T 48 | ScopeGuard scopeGuardIf(ScopeExitHandler&& handler) { 49 | return ScopeGuard(std::forward(handler)); 50 | } 51 | 52 | } // namespace stu 53 | 54 | -------------------------------------------------------------------------------- /STULabel/Internal/stu/Vector.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #include "stu/Vector.hpp" 4 | 5 | namespace stu { 6 | 7 | template struct detail::VectorBase; 8 | template struct detail::VectorBase; 9 | 10 | } // namespace stu 11 | -------------------------------------------------------------------------------- /STULabel/NSAttributedString+STUDynamicTypeFontScaling.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | NS_ASSUME_NONNULL_BEGIN 6 | 7 | @interface NSAttributedString (STUDynamicTypeScaling) 8 | 9 | - (NSAttributedString *) 10 | stu_copyWithFontsAdjustedForContentSizeCategory:(UIContentSizeCategory)category 11 | NS_RETURNS_RETAINED 12 | API_AVAILABLE(ios(10.0), tvos(10.0)); 13 | @end 14 | 15 | @interface NSMutableAttributedString (STUDynamicTypeScaling) 16 | 17 | - (void)stu_adjustFontsInRange:(NSRange)range 18 | forContentSizeCategory:(UIContentSizeCategory)category 19 | API_AVAILABLE(ios(10.0), tvos(10.0)); 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /STULabel/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleIdentifier 8 | $(PRODUCT_BUNDLE_IDENTIFIER) 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundleName 12 | $(PRODUCT_NAME) 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | $(CURRENT_PROJECT_VERSION) 19 | 20 | 21 | -------------------------------------------------------------------------------- /STULabel/Resources/ar.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "إضافة إلى جهات الاتصال"; 3 | 4 | "Add to Reading List" = "إضافة إلى قائمة القراءة"; 5 | 6 | "Call %@" = "اتصال بـ %@"; 7 | 8 | "Cancel" = "إلغاء"; 9 | 10 | "Copy" = "نسخ"; 11 | 12 | "Copy Email" = "نسخ البريد الإلكتروني"; 13 | 14 | "Copy Phone Number" = "نسخ رقم الهاتف"; 15 | 16 | "Drag Item" = "سحب العنصر"; 17 | 18 | "Links" = "الروابط"; 19 | 20 | "New Mail Message" = "رسالة بريد جديدة"; 21 | 22 | "Open" = "فتح"; 23 | 24 | "Open Link" = "فتح الرابط"; 25 | 26 | "Share…" = "مشاركة…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ca.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Afegir a Contactes"; 3 | 4 | "Add to Reading List" = "Afegir a la llista de lectura"; 5 | 6 | "Call %@" = "Trucar al %@"; 7 | 8 | "Cancel" = "Cancel·lar"; 9 | 10 | "Copy" = "Copiar"; 11 | 12 | "Copy Email" = "Copiar correu electrònic"; 13 | 14 | "Copy Phone Number" = "Copiar número de telèfon"; 15 | 16 | "Drag Item" = "Arrossegar l’ítem"; 17 | 18 | "Links" = "Enllaços"; 19 | 20 | "New Mail Message" = "Nou missatge de Mail"; 21 | 22 | "Open" = "Obrir"; 23 | 24 | "Open Link" = "Obrir l’enllaç"; 25 | 26 | "Share…" = "Compartir…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/cs.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Přidat do kontaktů"; 3 | 4 | "Add to Reading List" = "Přidat do seznamu četby"; 5 | 6 | "Call %@" = "Zavolat: %@"; 7 | 8 | "Cancel" = "Zrušit"; 9 | 10 | "Copy" = "Kopírovat"; 11 | 12 | "Copy Email" = "Zkopírovat e‑mail"; 13 | 14 | "Copy Phone Number" = "Zkopírovat telefonní číslo"; 15 | 16 | "Drag Item" = "Přetáhnout položku"; 17 | 18 | "Links" = "Odkazy"; 19 | 20 | "New Mail Message" = "Nová e‑mailová zpráva"; 21 | 22 | "Open" = "Otevřít"; 23 | 24 | "Open Link" = "Otevřít odkaz"; 25 | 26 | "Share…" = "Sdílet…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/da.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Føj til Kontakter"; 3 | 4 | "Add to Reading List" = "Føj til læselisten"; 5 | 6 | "Call %@" = "Ring til %@"; 7 | 8 | "Cancel" = "Annuller"; 9 | 10 | "Copy" = "Kopier"; 11 | 12 | "Copy Email" = "Kopier e‑mail"; 13 | 14 | "Copy Phone Number" = "Kopier telefonnummer"; 15 | 16 | "Drag Item" = "Træk objekt"; 17 | 18 | "Links" = "Links"; 19 | 20 | "New Mail Message" = "Ny Mail‐besked"; 21 | 22 | "Open" = "Åbn"; 23 | 24 | "Open Link" = "Åbn link"; 25 | 26 | "Share…" = "Del…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Zu Kontakten"; 3 | 4 | "Add to Reading List" = "Zur Leseliste hinzufügen"; 5 | 6 | "Call %@" = "%@ anrufen"; 7 | 8 | "Cancel" = "Abbrechen"; 9 | 10 | "Copy" = "Kopieren"; 11 | 12 | "Copy Email" = "E‑Mail kopieren"; 13 | 14 | "Copy Phone Number" = "Telefonnummer kopieren"; 15 | 16 | "Drag Item" = "Objekt ziehen"; 17 | 18 | "Links" = "Links"; 19 | 20 | "New Mail Message" = "Neue E‑Mail"; 21 | 22 | "Open" = "Öffnen"; 23 | 24 | "Open Link" = "Link öffnen"; 25 | 26 | "Share…" = "Teilen …"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/el.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Προσθήκη σε Επαφές"; 3 | 4 | "Add to Reading List" = "Προσθήκη στη Λίστα ανάγνωσης"; 5 | 6 | "Call %@" = "Κλήση προς %@"; 7 | 8 | "Cancel" = "Ακύρωση"; 9 | 10 | "Copy" = "Αντιγραφή"; 11 | 12 | "Copy Email" = "Αντιγραφή email"; 13 | 14 | "Copy Phone Number" = "Αντιγραφή αριθμού τηλεφώνου"; 15 | 16 | "Drag Item" = "Σύρετε το στοιχείο"; 17 | 18 | "Links" = "Συνδέσεις"; 19 | 20 | "New Mail Message" = "Νέο μήνυμα Mail"; 21 | 22 | "Open" = "Άνοιγμα"; 23 | 24 | "Open Link" = "Άνοιγμα συνδέσμου"; 25 | 26 | "Share…" = "Μοιραστείτε…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Add to Contacts"; 3 | 4 | "Add to Reading List" = "Add to Reading List"; 5 | 6 | "Call %@" = "Call %@"; 7 | 8 | "Cancel" = "Cancel"; 9 | 10 | "Copy" = "Copy"; 11 | 12 | "Copy Email" = "Copy Email"; 13 | 14 | "Copy Phone Number" = "Copy Phone Number"; 15 | 16 | "Drag Item" = "Drag Item"; 17 | 18 | "Links" = "Links"; 19 | 20 | "New Mail Message" = "New Mail Message"; 21 | 22 | "Open" = "Open"; 23 | 24 | "Open Link" = "Open Link"; 25 | 26 | "Share…" = "Share…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/es-419.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Agregar a Contactos"; 3 | 4 | "Add to Reading List" = "Agregar a la lista de lectura"; 5 | 6 | "Call %@" = "Llamar al %@"; 7 | 8 | "Cancel" = "Cancelar"; 9 | 10 | "Copy" = "Copiar"; 11 | 12 | "Copy Email" = "Copiar correo electrónico"; 13 | 14 | "Copy Phone Number" = "Copiar número de teléfono"; 15 | 16 | "Drag Item" = "Arrastrar elemento"; 17 | 18 | "Links" = "Enlaces"; 19 | 20 | "New Mail Message" = "Nuevo mensaje de correo"; 21 | 22 | "Open" = "Abrir"; 23 | 24 | "Open Link" = "Abrir enlace"; 25 | 26 | "Share…" = "Compartir…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Añadir a Contactos"; 3 | 4 | "Add to Reading List" = "Añadir a la lista de lectura"; 5 | 6 | "Call %@" = "Llamar al %@"; 7 | 8 | "Cancel" = "Cancelar"; 9 | 10 | "Copy" = "Copiar"; 11 | 12 | "Copy Email" = "Copiar correo electrónico"; 13 | 14 | "Copy Phone Number" = "Copiar número de teléfono"; 15 | 16 | "Drag Item" = "Arrastrar ítem"; 17 | 18 | "Links" = "Enlaces"; 19 | 20 | "New Mail Message" = "Nuevo mensaje de correo"; 21 | 22 | "Open" = "Abrir"; 23 | 24 | "Open Link" = "Abrir enlace"; 25 | 26 | "Share…" = "Compartir…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/fi.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Lisää yhteystietoihin"; 3 | 4 | "Add to Reading List" = "Lisää lukulistalle"; 5 | 6 | "Call %@" = "Soita %@"; 7 | 8 | "Cancel" = "Kumoa"; 9 | 10 | "Copy" = "Kopioi"; 11 | 12 | "Copy Email" = "Kopioi sähköposti"; 13 | 14 | "Copy Phone Number" = "Kopioi puhelinnumero"; 15 | 16 | "Drag Item" = "Vedä kohde"; 17 | 18 | "Links" = "Linkit"; 19 | 20 | "New Mail Message" = "Uusi sähköpostiviesti"; 21 | 22 | "Open" = "Avaa"; 23 | 24 | "Open Link" = "Avaa linkki"; 25 | 26 | "Share…" = "Jaa…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/fr-CA.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Ajouter aux contacts"; 3 | 4 | "Add to Reading List" = "Ajouter à la liste de lecture"; 5 | 6 | "Call %@" = "Composer le %@"; 7 | 8 | "Cancel" = "Annuler"; 9 | 10 | "Copy" = "Copier"; 11 | 12 | "Copy Email" = "Copier le courriel"; 13 | 14 | "Copy Phone Number" = "Copier le numéro de téléphone"; 15 | 16 | "Drag Item" = "Faire glisser l’élément"; 17 | 18 | "Links" = "Liens"; 19 | 20 | "New Mail Message" = "Nouveau courriel"; 21 | 22 | "Open" = "Ouvrir"; 23 | 24 | "Open Link" = "Ouvrir le lien"; 25 | 26 | "Share…" = "Partager…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Ajouter aux contacts"; 3 | 4 | "Add to Reading List" = "Ajouter à la liste de lecture"; 5 | 6 | "Call %@" = "Composer le %@"; 7 | 8 | "Cancel" = "Annuler"; 9 | 10 | "Copy" = "Copier"; 11 | 12 | "Copy Email" = "Copier l’e‑mail"; 13 | 14 | "Copy Phone Number" = "Copier le numéro de téléphone"; 15 | 16 | "Drag Item" = "Faire glisser l’élément"; 17 | 18 | "Links" = "Liens"; 19 | 20 | "New Mail Message" = "Nouveau message Mail"; 21 | 22 | "Open" = "Ouvrir"; 23 | 24 | "Open Link" = "Ouvrir le lien"; 25 | 26 | "Share…" = "Partager…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/he.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "הוסף לאנשי קשר"; 3 | 4 | "Add to Reading List" = "הוסף לרשימת הקריאה"; 5 | 6 | "Call %@" = "התקשר ל-‪%@‬"; 7 | 8 | "Cancel" = "ביטול"; 9 | 10 | "Copy" = "העתק"; 11 | 12 | "Copy Email" = "העתק דוא״ל"; 13 | 14 | "Copy Phone Number" = "העתק מספר טלפון"; 15 | 16 | "Drag Item" = "גרור פריט"; 17 | 18 | "Links" = "קישורים"; 19 | 20 | "New Mail Message" = "הודעת דואר חדשה"; 21 | 22 | "Open" = "פתח"; 23 | 24 | "Open Link" = "פתח את הקישור"; 25 | 26 | "Share…" = "שתף…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/hi.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "संपर्क में जोड़ें"; 3 | 4 | "Add to Reading List" = "पठन सूची में जोड़ें"; 5 | 6 | "Call %@" = "%@ को कॉल करें"; 7 | 8 | "Cancel" = "रद्द करें"; 9 | 10 | "Copy" = "कॉपी"; 11 | 12 | "Copy Email" = "ईमेल कॉपी करें"; 13 | 14 | "Copy Phone Number" = "फ़ोन नंबर कॉपी करें"; 15 | 16 | "Drag Item" = "आइटम ड्रैग करें"; 17 | 18 | "Links" = "लिंक"; 19 | 20 | "New Mail Message" = "नया मेल संदेश"; 21 | 22 | "Open" = "खोलें"; 23 | 24 | "Open Link" = "लिंक खोलें"; 25 | 26 | "Share…" = "शेयर करें…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/hr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Dodaj u Kontakte"; 3 | 4 | "Add to Reading List" = "Dodaj na popis za čitanje"; 5 | 6 | "Call %@" = "Nazovi: %@"; 7 | 8 | "Cancel" = "Poništi"; 9 | 10 | "Copy" = "Kopiraj"; 11 | 12 | "Copy Email" = "Kopiranje e‐pošte"; 13 | 14 | "Copy Phone Number" = "Kopiraj telefonski broj"; 15 | 16 | "Drag Item" = "Povucite stavku"; 17 | 18 | "Links" = "Linkovi"; 19 | 20 | "New Mail Message" = "Nova Mail poruka"; 21 | 22 | "Open" = "Otvori"; 23 | 24 | "Open Link" = "Otvori link"; 25 | 26 | "Share…" = "Dijeli…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/hu.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Hozzáadás a kapcsolatokhoz"; 3 | 4 | "Add to Reading List" = "Hozzáadás az olvasási listához"; 5 | 6 | "Call %@" = "%@ hívása"; 7 | 8 | "Cancel" = "Mégsem"; 9 | 10 | "Copy" = "Másolás"; 11 | 12 | "Copy Email" = "E‑mail cím másolása"; 13 | 14 | "Copy Phone Number" = "Telefonszám másolása"; 15 | 16 | "Drag Item" = "Húzza az elemet"; 17 | 18 | "Links" = "Linkek"; 19 | 20 | "New Mail Message" = "Új Mail‐üzenet"; 21 | 22 | "Open" = "Megnyitás"; 23 | 24 | "Open Link" = "Link megnyitása"; 25 | 26 | "Share…" = "Megosztás…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/id.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Tambah ke Kontak"; 3 | 4 | "Add to Reading List" = "Tambahkan ke Daftar Bacaan"; 5 | 6 | "Call %@" = "Panggil %@"; 7 | 8 | "Cancel" = "Batalkan"; 9 | 10 | "Copy" = "Salin"; 11 | 12 | "Copy Email" = "Salin Email"; 13 | 14 | "Copy Phone Number" = "Salin Nomor Telepon"; 15 | 16 | "Drag Item" = "Seret Item"; 17 | 18 | "Links" = "Tautan"; 19 | 20 | "New Mail Message" = "Pesan Mail Baru"; 21 | 22 | "Open" = "Buka"; 23 | 24 | "Open Link" = "Buka Tautan"; 25 | 26 | "Share…" = "Bagikan…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Aggiungi a contatti"; 3 | 4 | "Add to Reading List" = "Aggiungi alla lista di lettura"; 5 | 6 | "Call %@" = "Chiama %@"; 7 | 8 | "Cancel" = "Annulla"; 9 | 10 | "Copy" = "Copia"; 11 | 12 | "Copy Email" = "Copia e‑mail"; 13 | 14 | "Copy Phone Number" = "Copia numero telefonico"; 15 | 16 | "Drag Item" = "Trascina elemento"; 17 | 18 | "Links" = "Link"; 19 | 20 | "New Mail Message" = "Nuovo messaggio e‑mail"; 21 | 22 | "Open" = "Apri"; 23 | 24 | "Open Link" = "Apri link"; 25 | 26 | "Share…" = "Condividi…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "連絡先に追加"; 3 | 4 | "Add to Reading List" = "リーディングリストに追加"; 5 | 6 | "Call %@" = "%@に発信"; 7 | 8 | "Cancel" = "キャンセル"; 9 | 10 | "Copy" = "コピー"; 11 | 12 | "Copy Email" = "メールをコピー"; 13 | 14 | "Copy Phone Number" = "電話番号をコピー"; 15 | 16 | "Drag Item" = "項目をドラッグ"; 17 | 18 | "Links" = "リンク"; 19 | 20 | "New Mail Message" = "新規メールメッセージ"; 21 | 22 | "Open" = "開く"; 23 | 24 | "Open Link" = "リンクを開く"; 25 | 26 | "Share…" = "共有…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ko.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "연락처에 추가"; 3 | 4 | "Add to Reading List" = "읽기 목록에 추가"; 5 | 6 | "Call %@" = "%@에 연결"; 7 | 8 | "Cancel" = "취소"; 9 | 10 | "Copy" = "복사"; 11 | 12 | "Copy Email" = "이메일 복사"; 13 | 14 | "Copy Phone Number" = "전화번호 복사"; 15 | 16 | "Drag Item" = "항목 드래그"; 17 | 18 | "Links" = "링크"; 19 | 20 | "New Mail Message" = "새로운 Mail 메시지"; 21 | 22 | "Open" = "열기"; 23 | 24 | "Open Link" = "링크 열기"; 25 | 26 | "Share…" = "공유…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ms.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Tambah ke Kenalan"; 3 | 4 | "Add to Reading List" = "Tambah ke Senarai Bacaan"; 5 | 6 | "Call %@" = "Panggil %@"; 7 | 8 | "Cancel" = "Batal"; 9 | 10 | "Copy" = "Salin"; 11 | 12 | "Copy Email" = "Salin E‑mel"; 13 | 14 | "Copy Phone Number" = "Salin Nombor Telefon"; 15 | 16 | "Drag Item" = "Seret Item"; 17 | 18 | "Links" = "Pautan"; 19 | 20 | "New Mail Message" = "Mesej Mail Baru"; 21 | 22 | "Open" = "Buka"; 23 | 24 | "Open Link" = "Buka Pautan"; 25 | 26 | "Share…" = "Kongsi…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/nb.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Legg til i kontakter"; 3 | 4 | "Add to Reading List" = "Legg til i leselisten"; 5 | 6 | "Call %@" = "Ring %@"; 7 | 8 | "Cancel" = "Avbryt"; 9 | 10 | "Copy" = "Kopier"; 11 | 12 | "Copy Email" = "Kopier e‑postadresse"; 13 | 14 | "Copy Phone Number" = "Kopier telefonnummer"; 15 | 16 | "Drag Item" = "Dra objekt"; 17 | 18 | "Links" = "Koblinger"; 19 | 20 | "New Mail Message" = "Ny e‑postmelding"; 21 | 22 | "Open" = "Åpne"; 23 | 24 | "Open Link" = "Åpne kobling"; 25 | 26 | "Share…" = "Del…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/nl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Zet in contacten"; 3 | 4 | "Add to Reading List" = "Toevoegen aan leeslijst"; 5 | 6 | "Call %@" = "Bel %@"; 7 | 8 | "Cancel" = "Annuleer"; 9 | 10 | "Copy" = "Kopieer"; 11 | 12 | "Copy Email" = "Kopieer e‑mail"; 13 | 14 | "Copy Phone Number" = "Kopieer telefoonnummer"; 15 | 16 | "Drag Item" = "Sleep object"; 17 | 18 | "Links" = "Links"; 19 | 20 | "New Mail Message" = "Nieuw Mail‐bericht"; 21 | 22 | "Open" = "Open"; 23 | 24 | "Open Link" = "Open link"; 25 | 26 | "Share…" = "Deel…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/pl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Do kontaktów"; 3 | 4 | "Add to Reading List" = "Dodaj do listy Czytelnia"; 5 | 6 | "Call %@" = "Połącz z %@"; 7 | 8 | "Cancel" = "Anuluj"; 9 | 10 | "Copy" = "Kopiuj"; 11 | 12 | "Copy Email" = "Kopiuj adres e‑mail"; 13 | 14 | "Copy Phone Number" = "Kopiuj numer telefonu"; 15 | 16 | "Drag Item" = "Przeciągnij element"; 17 | 18 | "Links" = "Łącza"; 19 | 20 | "New Mail Message" = "Nowa wiadomość Mail"; 21 | 22 | "Open" = "Otwórz"; 23 | 24 | "Open Link" = "Otwórz łącze"; 25 | 26 | "Share…" = "Udostępnij…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/pt-PT.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Adicionar aos contactos"; 3 | 4 | "Add to Reading List" = "Adicionar à lista de leitura"; 5 | 6 | "Call %@" = "Ligar para %@"; 7 | 8 | "Cancel" = "Cancelar"; 9 | 10 | "Copy" = "Copiar"; 11 | 12 | "Copy Email" = "Copiar e‑mail"; 13 | 14 | "Copy Phone Number" = "Copiar número de telefone"; 15 | 16 | "Drag Item" = "Arrastar item"; 17 | 18 | "Links" = "Ligações"; 19 | 20 | "New Mail Message" = "Nova mensagem do Mail"; 21 | 22 | "Open" = "Abrir"; 23 | 24 | "Open Link" = "Abrir ligação"; 25 | 26 | "Share…" = "Partilhar…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/pt.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Adicionar aos Contatos"; 3 | 4 | "Add to Reading List" = "Adicionar à Lista de Leitura"; 5 | 6 | "Call %@" = "Ligar para %@"; 7 | 8 | "Cancel" = "Cancelar"; 9 | 10 | "Copy" = "Copiar"; 11 | 12 | "Copy Email" = "Copiar E‑mail"; 13 | 14 | "Copy Phone Number" = "Copiar Número de Telefone"; 15 | 16 | "Drag Item" = "Arrastar Item"; 17 | 18 | "Links" = "Links"; 19 | 20 | "New Mail Message" = "Nova Mensagem do Mail"; 21 | 22 | "Open" = "Abrir"; 23 | 24 | "Open Link" = "Abrir Link"; 25 | 26 | "Share…" = "Compartilhar…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ro.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Adăugați la Contacte"; 3 | 4 | "Add to Reading List" = "Adăugați la lista de lectură"; 5 | 6 | "Call %@" = "Apelați %@"; 7 | 8 | "Cancel" = "Anulați"; 9 | 10 | "Copy" = "Copiați"; 11 | 12 | "Copy Email" = "Copiați e‑mailul"; 13 | 14 | "Copy Phone Number" = "Copiați numărul de telefon"; 15 | 16 | "Drag Item" = "Trageți elementul"; 17 | 18 | "Links" = "Linkuri"; 19 | 20 | "New Mail Message" = "Mesaj Mail nou"; 21 | 22 | "Open" = "Deschideți"; 23 | 24 | "Open Link" = "Deschideți linkul"; 25 | 26 | "Share…" = "Partajați…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Добавить в контакты"; 3 | 4 | "Add to Reading List" = "Добавить в Список для чтения"; 5 | 6 | "Call %@" = "Набрать %@"; 7 | 8 | "Cancel" = "Отменить"; 9 | 10 | "Copy" = "Скопировать"; 11 | 12 | "Copy Email" = "Скопировать e‑mail"; 13 | 14 | "Copy Phone Number" = "Скопировать номер телефона"; 15 | 16 | "Drag Item" = "Перетянуть объект"; 17 | 18 | "Links" = "Ссылки"; 19 | 20 | "New Mail Message" = "Новое письмо"; 21 | 22 | "Open" = "Открыть"; 23 | 24 | "Open Link" = "Открыть ссылку"; 25 | 26 | "Share…" = "Поделиться…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/sk.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Pridať do kontaktov"; 3 | 4 | "Add to Reading List" = "Pridať do zoznamu Na prečítanie"; 5 | 6 | "Call %@" = "Zavolať %@"; 7 | 8 | "Cancel" = "Zrušiť"; 9 | 10 | "Copy" = "Kopírovať"; 11 | 12 | "Copy Email" = "Kopírovať e‑mail"; 13 | 14 | "Copy Phone Number" = "Kopírovať telefónne číslo"; 15 | 16 | "Drag Item" = "Potiahnuť položku"; 17 | 18 | "Links" = "Odkazy"; 19 | 20 | "New Mail Message" = "Nový email"; 21 | 22 | "Open" = "Otvoriť"; 23 | 24 | "Open Link" = "Otvoriť odkaz"; 25 | 26 | "Share…" = "Zdieľať…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/sv.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Lägg till i kontakter"; 3 | 4 | "Add to Reading List" = "Lägg till i läslistan"; 5 | 6 | "Call %@" = "Ring %@"; 7 | 8 | "Cancel" = "Avbryt"; 9 | 10 | "Copy" = "Kopiera"; 11 | 12 | "Copy Email" = "Kopiera e‑post"; 13 | 14 | "Copy Phone Number" = "Kopiera telefonnummer"; 15 | 16 | "Drag Item" = "Dra objekt"; 17 | 18 | "Links" = "Länkar"; 19 | 20 | "New Mail Message" = "Nytt brev i Mail"; 21 | 22 | "Open" = "Öppna"; 23 | 24 | "Open Link" = "Öppna länk"; 25 | 26 | "Share…" = "Dela…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/th.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "เพิ่มไปยังรายชื่อ"; 3 | 4 | "Add to Reading List" = "เพิ่มไปยังรายการอ่าน"; 5 | 6 | "Call %@" = "โทรหา %@"; 7 | 8 | "Cancel" = "ยกเลิก"; 9 | 10 | "Copy" = "คัดลอก"; 11 | 12 | "Copy Email" = "คัดลอกอีเมล"; 13 | 14 | "Copy Phone Number" = "คัดลอกเบอร์โทรศัพท์"; 15 | 16 | "Drag Item" = "ลากรายการ"; 17 | 18 | "Links" = "ลิงก์"; 19 | 20 | "New Mail Message" = "ข้อความเมลใหม่"; 21 | 22 | "Open" = "เปิด"; 23 | 24 | "Open Link" = "เปิดลิงก์"; 25 | 26 | "Share…" = "แชร์…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/tr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Kişilere Ekle"; 3 | 4 | "Add to Reading List" = "Okuma Listesine Ekle"; 5 | 6 | "Call %@" = "Ara: %@"; 7 | 8 | "Cancel" = "Vazgeç"; 9 | 10 | "Copy" = "Kopyala"; 11 | 12 | "Copy Email" = "E‑postayı Kopyala"; 13 | 14 | "Copy Phone Number" = "Telefon Numarasını Kopyala"; 15 | 16 | "Drag Item" = "Öğeyi Sürükle"; 17 | 18 | "Links" = "Bağlantılar"; 19 | 20 | "New Mail Message" = "Yeni Mail İletisi"; 21 | 22 | "Open" = "Aç"; 23 | 24 | "Open Link" = "Bağlantıyı Aç"; 25 | 26 | "Share…" = "Paylaş…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/uk.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Додати в контакти"; 3 | 4 | "Add to Reading List" = "додати до списку читання"; 5 | 6 | "Call %@" = "Подзвонити %@"; 7 | 8 | "Cancel" = "Скасувати"; 9 | 10 | "Copy" = "Копіювати"; 11 | 12 | "Copy Email" = "Копіювати е‐адресу"; 13 | 14 | "Copy Phone Number" = "Копіювати номер телефону"; 15 | 16 | "Drag Item" = "Тягти обʼєкт"; 17 | 18 | "Links" = "Посилання"; 19 | 20 | "New Mail Message" = "Новий е‐лист"; 21 | 22 | "Open" = "Відкрити"; 23 | 24 | "Open Link" = "Відкрити посилання"; 25 | 26 | "Share…" = "Поділитися…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/vi.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "Thêm vào Danh bạ"; 3 | 4 | "Add to Reading List" = "Thêm vào Danh sách đọc"; 5 | 6 | "Call %@" = "Gọi %@"; 7 | 8 | "Cancel" = "Hủy"; 9 | 10 | "Copy" = "Sao chép"; 11 | 12 | "Copy Email" = "Sao chép email"; 13 | 14 | "Copy Phone Number" = "Sao chép số điện thoại"; 15 | 16 | "Drag Item" = "Kéo mục"; 17 | 18 | "Links" = "Liên kết"; 19 | 20 | "New Mail Message" = "Thư mới trong Mail"; 21 | 22 | "Open" = "Mở"; 23 | 24 | "Open Link" = "Mở liên kết"; 25 | 26 | "Share…" = "Chia sẻ…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "添加到通讯录"; 3 | 4 | "Add to Reading List" = "添加到阅读列表"; 5 | 6 | "Call %@" = "拨打 %@"; 7 | 8 | "Cancel" = "取消"; 9 | 10 | "Copy" = "拷贝"; 11 | 12 | "Copy Email" = "拷贝电子邮件"; 13 | 14 | "Copy Phone Number" = "拷贝电话号码"; 15 | 16 | "Drag Item" = "拖移项目"; 17 | 18 | "Links" = "链接"; 19 | 20 | "New Mail Message" = "新建邮件信息"; 21 | 22 | "Open" = "打开"; 23 | 24 | "Open Link" = "打开链接"; 25 | 26 | "Share…" = "共享…"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/zh-Hant-HK.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "添加到通訊錄"; 3 | 4 | "Add to Reading List" = "添加到閱讀列表"; 5 | 6 | "Call %@" = "撥打 %@"; 7 | 8 | "Cancel" = "取消"; 9 | 10 | "Copy" = "複製"; 11 | 12 | "Copy Email" = "複製電子郵件"; 13 | 14 | "Copy Phone Number" = "複製電話號碼"; 15 | 16 | "Drag Item" = "拖移項目"; 17 | 18 | "Links" = "連結"; 19 | 20 | "New Mail Message" = "新增郵件"; 21 | 22 | "Open" = "開啟"; 23 | 24 | "Open Link" = "開啟連結"; 25 | 26 | "Share…" = "分享⋯"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/Resources/zh-Hant.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | "Add to Contacts" = "添加到通訊錄"; 3 | 4 | "Add to Reading List" = "添加到閱讀列表"; 5 | 6 | "Call %@" = "撥打 %@"; 7 | 8 | "Cancel" = "取消"; 9 | 10 | "Copy" = "拷貝"; 11 | 12 | "Copy Email" = "拷貝電子郵件"; 13 | 14 | "Copy Phone Number" = "拷貝電話號碼"; 15 | 16 | "Drag Item" = "拖移項目"; 17 | 18 | "Links" = "連結"; 19 | 20 | "New Mail Message" = "新增郵件"; 21 | 22 | "Open" = "開啟"; 23 | 24 | "Open Link" = "打開連結"; 25 | 26 | "Share…" = "分享⋯"; 27 | 28 | -------------------------------------------------------------------------------- /STULabel/STUBackgroundAttribute-Internal.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STUBackgroundAttribute.h" 4 | 5 | @interface STUBackgroundAttribute () { 6 | @package 7 | UIColor *_color; 8 | bool _fillTextLineGaps; 9 | bool _extendTextLinesToCommonHorizontalBounds; 10 | CGFloat _cornerRadius; 11 | UIEdgeInsets _edgeInsets; 12 | UIColor *_borderColor; 13 | CGFloat _borderWidth; 14 | } 15 | @end 16 | -------------------------------------------------------------------------------- /STULabel/STUCancellationFlag.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #import "STUDefines.h" 6 | 7 | #import 8 | #import 9 | 10 | STU_ASSUME_NONNULL_AND_STRONG_BEGIN 11 | 12 | /// @note 13 | /// @c STUCancellationFlag values are NOT reference-counted. You must manually ensure that a 14 | /// @c STUCancellationFlag instance remains valid and is not moved in memory while it is being 15 | /// used. 16 | /// @warning 17 | /// Swift 4 does not support using @c STUCancellationFlag and similar C structs wrapping atomic 18 | /// variables directly in Swift properties or local variables, 19 | /// see https://twitter.com/jckarter/status/962776179269775360 20 | typedef struct STUCancellationFlag { 21 | _Atomic(bool) isCancelled; 22 | } STUCancellationFlag; 23 | 24 | /// Sets the value of the cancellation flag to true. 25 | static STU_INLINE 26 | void STUCancellationFlagSetCancelled(STUCancellationFlag *token) { 27 | atomic_store_explicit(&token->isCancelled, true, memory_order_relaxed); 28 | } 29 | 30 | /// @returns The current value of the cancellation flag. 31 | /// 32 | /// @note This function uses a relaxed memory order load, so calling this function does NOT 33 | /// establish a "happens-before" relationship with a previous call to 34 | /// @c STUCancellationFlagSetCancelled (unless you add the appropriate fences). 35 | static STU_INLINE __attribute__((warn_unused_result)) 36 | bool STUCancellationFlagGetValue(const STUCancellationFlag *token) { 37 | // http://www.open-std.org/jtc1/SC22/WG14/www/docs/dr_459.htm 38 | return STU_UNLIKELY(atomic_load_explicit((_Atomic(bool)*)&token->isCancelled, // const cast 39 | memory_order_relaxed)); 40 | } 41 | 42 | STU_ASSUME_NONNULL_AND_STRONG_END 43 | -------------------------------------------------------------------------------- /STULabel/STULabel.modulemap: -------------------------------------------------------------------------------- 1 | framework module STULabel { 2 | 3 | header "NSLayoutAnchor+STULabelSpacing.h" 4 | header "STUBackgroundAttribute.h" 5 | header "STUCancellationFlag.h" 6 | header "STUDefines.h" 7 | header "STULabel.h" 8 | header "STULabelAlignment.h" 9 | header "STULabelDrawingBlock.h" 10 | header "STULabelLayer.h" 11 | header "STULabelLayoutInfo.h" 12 | header "STULabelOverlayStyle.h" 13 | header "STULabelPrerenderer.h" 14 | header "STULayerWithNullDefaultActions.h" 15 | header "STUParagraphStyle.h" 16 | header "STUShapedString.h" 17 | header "STUStartEndRange.h" 18 | header "STUTextAttachment.h" 19 | header "STUTextAttributes.h" 20 | header "STUTextFlags.h" 21 | header "STUTextFrame.h" 22 | header "STUTextFrameAccessibilityElement.h" 23 | header "STUTextFrameDrawingOptions.h" 24 | header "STUTextFrameOptions.h" 25 | header "STUTextFrameRange.h" 26 | header "STUTextHighlightStyle.h" 27 | header "STUTextLink.h" 28 | header "STUTextRange.h" 29 | header "STUTextRectArray.h" 30 | header "STUTruncationScope.h" 31 | 32 | export * 33 | 34 | explicit module Unsafe { 35 | header "STUTextFrame-Unsafe.h" 36 | header "STUTextFrameLine.h" 37 | export * 38 | } 39 | 40 | explicit module DynamicTypeFontScaling { 41 | header "NSAttributedString+STUDynamicTypeFontScaling.h" 42 | header "UIFont+STUDynamicTypeFontScaling.h" 43 | export * 44 | } 45 | 46 | explicit module ImageUtils { 47 | header "STUImageUtils.h" 48 | export * 49 | } 50 | 51 | explicit module MainScreenProperties { 52 | header "STUMainScreenProperties.h" 53 | export * 54 | } 55 | 56 | explicit module Mutex { 57 | header "stu_mutex.h" 58 | export * 59 | } 60 | 61 | explicit module ObjCRuntimeWrappers { 62 | header "STUObjCRuntimeWrappers.h" 63 | export * 64 | } 65 | 66 | explicit module SwiftExtensions { 67 | header "STULabelSwiftExtensions.h" 68 | export * 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /STULabel/STULabelAlignment.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | typedef NS_CLOSED_ENUM(uint8_t, STULabelHorizontalAlignment) { 8 | STULabelHorizontalAlignmentLeft = 0, 9 | STULabelHorizontalAlignmentRight = 1, 10 | STULabelHorizontalAlignmentCenter = 2 11 | }; 12 | enum { STULabelHorizontalAlignmentBitSize STU_SWIFT_UNAVAILABLE = 2 }; 13 | 14 | typedef NS_CLOSED_ENUM(uint8_t, STULabelVerticalAlignment) { 15 | STULabelVerticalAlignmentTop = 0, 16 | STULabelVerticalAlignmentBottom = 1, 17 | STULabelVerticalAlignmentCenter = 2, 18 | STULabelVerticalAlignmentCenterCapHeight = 3, 19 | STULabelVerticalAlignmentCenterXHeight = 4 20 | }; 21 | enum { STULabelVerticalAlignmentBitSize STU_SWIFT_UNAVAILABLE = 3 }; 22 | 23 | /// Alignment mode for text paragraphs that have no associated @c NSParagraphStyle attribute 24 | /// or have a paragraph style attribute whose @c baseWritingDirection property is @c .natural and 25 | /// whose @c textAlignment property is @c .natural or @c .justified`. (If either of these two 26 | /// properties has a different value, it determines the paragraph's alignment.) 27 | typedef NS_CLOSED_ENUM(uint8_t, STULabelDefaultTextAlignment) { 28 | /// Left-aligned if the label's @c effectiveUserInterfaceLayoutDirection is @c .leftToRight, 29 | /// otherwise right-aligned. 30 | STULabelDefaultTextAlignmentLeading = 0, 31 | /// Right-aligned if the label's @c effectiveUserInterfaceLayoutDirection is @c .leftToRight, 32 | /// otherwise left-aligned. 33 | STULabelDefaultTextAlignmentTrailing = 1, 34 | /// Left-aligned if the paragraph's detected base writing direction is left-to-right, 35 | /// otherwise right-aligned. 36 | STULabelDefaultTextAlignmentTextStart = 2, 37 | /// Right-aligned if the paragraph's detected base writing direction is left-to-right, 38 | /// otherwise left-aligned. 39 | STULabelDefaultTextAlignmentTextEnd = 3 40 | }; 41 | enum { STULabelDefaultTextAlignmentBitSize STU_SWIFT_UNAVAILABLE = 2 }; 42 | -------------------------------------------------------------------------------- /STULabel/STULabelDrawingBlock-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabelDrawingBlock.h" 4 | 5 | #import "STUTextFrame-Internal.hpp" 6 | 7 | namespace stu_label { 8 | 9 | STULabelDrawingBlockParameters * 10 | createLabelDrawingBlockParametersInstance( 11 | STUTextFrame *textFrame, STUTextFrameRange range, CGPoint textFrameOrigin, 12 | CGContextRef context, ContextBaseCTM_d, PixelAlignBaselines, 13 | STUTextFrameDrawingOptions * __nullable options, 14 | const STUCancellationFlag * __nullable cancellationFlag) 15 | NS_RETURNS_RETAINED; 16 | 17 | } // namespace stu_label 18 | -------------------------------------------------------------------------------- /STULabel/STULabelDrawingBlock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextFrame.h" 4 | 5 | STU_ASSUME_NONNULL_AND_STRONG_BEGIN 6 | 7 | STU_EXPORT 8 | @interface STULabelDrawingBlockParameters : NSObject 9 | 10 | @property (readonly) STUTextFrame *textFrame NS_REFINED_FOR_SWIFT; 11 | // var textFrame: STUTextFrameWithOrigin 12 | 13 | @property (readonly) STUTextFrameRange range NS_REFINED_FOR_SWIFT; 14 | // var indices: Range 15 | 16 | @property (readonly) CGPoint textFrameOrigin NS_REFINED_FOR_SWIFT; 17 | 18 | @property (readonly) CGContextRef context; 19 | 20 | @property (readonly) CGFloat contextBaseCTM_d; 21 | 22 | @property (readonly) bool pixelAlignBaselines; 23 | 24 | @property (readonly, nullable) STUTextFrameDrawingOptions *options; 25 | 26 | @property (readonly, nullable) const STUCancellationFlag *cancellationFlag; 27 | 28 | - (void)draw; 29 | 30 | - (nonnull instancetype)init NS_UNAVAILABLE; 31 | 32 | @end 33 | 34 | /// Must be thread-safe. 35 | typedef void (^ STULabelDrawingBlock)(STULabelDrawingBlockParameters *params); 36 | 37 | typedef NS_ENUM(uint8_t, STULabelDrawingBounds) { 38 | STULabelTextImageBounds = 1, 39 | STULabelTextLayoutBounds = 2, 40 | STULabelTextLayoutBoundsPlusInsets = 0, 41 | STULabelViewBounds = 3 42 | }; 43 | enum { STULabelDrawingBoundsBitSize STU_SWIFT_UNAVAILABLE = 2 }; 44 | 45 | typedef NS_OPTIONS(uint8_t, STULabelDrawingBlockColorOptions) { 46 | /// Indicates that the drawing block only uses colors present in the content of the text frame, 47 | /// or other grayscale colors. 48 | STULabelDrawingBlockOnlyUsesTextColors = 1, 49 | /// Indicates that the drawing block needs a bitmap context with a wide-gamut color space and more 50 | /// than 8-bits per color channel for optimal display quality. 51 | STULabelDrawingBlockUsesExtendedColors = 2 52 | }; 53 | enum { STULabelDrawingBlockColorOptionsBitSize STU_SWIFT_UNAVAILABLE = 3 }; 54 | 55 | STU_ASSUME_NONNULL_AND_STRONG_END 56 | -------------------------------------------------------------------------------- /STULabel/STULabelLayer-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabelLayer.h" 4 | 5 | #import "STUImageUtils.h" 6 | 7 | #import "Internal/Unretained.hpp" 8 | 9 | @interface STULabelLayer () 10 | 11 | - (void)stu_didMoveToWindow:(UIWindow*)window; 12 | 13 | @property (nonatomic, setter=stu_setAlwaysUsesContentSublayer:) bool stu_alwaysUsesContentSublayer; 14 | 15 | @property (readonly, nullable) CALayer* stu_contentSublayer; 16 | 17 | @end 18 | 19 | namespace stu_label { 20 | struct LabelParameters; 21 | struct LabelTextFrameInfo; 22 | Unretained defaultLabelTextFrameOptions(); 23 | } 24 | 25 | // For some reason LabelLayer can't friend this function if the CGSize is returned by value. 26 | const CGSize& STULabelLayerGetSize(const STULabelLayer* __nonnull); 27 | 28 | CGFloat STULabelLayerGetScreenScale(const STULabelLayer* __nonnull); 29 | 30 | bool STULabelLayerIsAttributed(const STULabelLayer* __nonnull); 31 | 32 | const stu_label::LabelParameters& STULabelLayerGetParams(const STULabelLayer* __nonnull); 33 | 34 | NSInteger STULabelLayerGetMaximumNumberOfLines(const STULabelLayer* __nonnull); 35 | 36 | const stu_label::LabelTextFrameInfo& STULabelLayerGetCurrentTextFrameInfo(STULabelLayer* __nonnull); 37 | 38 | -------------------------------------------------------------------------------- /STULabel/STULabelLayoutInfo-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabelLayoutInfo.h" 4 | 5 | #import "Internal/TextFrame.hpp" 6 | 7 | namespace stu_label { 8 | 9 | struct LabelParameters; 10 | 11 | struct LabelTextFrameInfo { 12 | STUTextFrameFlags flags; 13 | STUTextLayoutMode textLayoutMode : STUTextLayoutModeBitSize; 14 | STULabelHorizontalAlignment horizontalAlignment : STULabelHorizontalAlignmentBitSize; 15 | STULabelVerticalAlignment verticalAlignment : STULabelVerticalAlignmentBitSize; 16 | bool isValid; 17 | Int32 lineCount; 18 | /// This rectangle is calculated from the frame's layoutBounds by extending the rectangle 19 | /// by the minimum amount required to ensure that the text has the horizontal and vertical 20 | /// alignment within the rectangle that was specified for the label. 21 | Rect layoutBounds; 22 | CGSize frameSize; 23 | Size minFrameSize; 24 | CGFloat firstBaseline; 25 | CGFloat lastBaseline; 26 | Float32 firstLineHeight; 27 | Float32 firstLineHeightAboveBaseline; 28 | Float32 lastLineHeight; 29 | Float32 lastLineHeightBelowBaseline; 30 | CGFloat textScaleFactor; 31 | 32 | bool isValidForSize(CGSize size, const DisplayScale& displayScale) const { 33 | return isValid && isValidForSizeImpl(size, displayScale); 34 | } 35 | 36 | CGSize sizeThatFits(const UIEdgeInsets&, const DisplayScale&) const; 37 | 38 | static const LabelTextFrameInfo empty; 39 | 40 | private: 41 | bool isValidForSizeImpl(CGSize, const DisplayScale&) const; 42 | }; 43 | 44 | LabelTextFrameInfo labelTextFrameInfo(const TextFrame&, STULabelVerticalAlignment, 45 | const DisplayScale&); 46 | 47 | CGPoint textFrameOriginInLayer(const LabelTextFrameInfo&, const LabelParameters& params); 48 | 49 | STULabelLayoutInfo stuLabelLayoutInfo(const LabelTextFrameInfo&, CGPoint textFrameOrigin, 50 | const DisplayScale&); 51 | 52 | } // namespace stu_label 53 | -------------------------------------------------------------------------------- /STULabel/STULabelPrerenderer-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STULabelPrerenderer.h" 4 | 5 | namespace stu_label { 6 | class LabelPrerenderer; 7 | 8 | namespace detail { void labelPrerendererObjCObjectWasDestroyed(LabelPrerenderer&); } 9 | } 10 | 11 | STU_EXTERN_C_BEGIN 12 | 13 | @interface STULabelPrerenderer () { 14 | @package 15 | stu_label::LabelPrerenderer* prerenderer; 16 | } 17 | @end 18 | 19 | STULabelPrerenderer* STULabelPrerendererAlloc(Class prerendererClass) NS_RETURNS_RETAINED; 20 | 21 | STU_EXTERN_C_END 22 | -------------------------------------------------------------------------------- /STULabel/STULabelPrerenderer-no-ARC.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #if __has_feature(objc_arc) 4 | #error This file must be compiled with -fno-objc-arc 5 | #endif 6 | 7 | #import "STULabelPrerenderer-Internal.hpp" 8 | 9 | #import 10 | 11 | @implementation STULabelPrerenderer 12 | 13 | + (instancetype)allocWithZone:(struct _NSZone* __unused)zone { 14 | return STULabelPrerendererAlloc(self); 15 | } 16 | 17 | STU_DISABLE_CLANG_WARNING("-Wobjc-missing-super-calls") 18 | - (void)dealloc { 19 | stu_label::LabelPrerenderer& p = *self->prerenderer; 20 | objc_destructInstance(self); 21 | stu_label::detail::labelPrerendererObjCObjectWasDestroyed(p); 22 | } 23 | STU_REENABLE_CLANG_WARNING 24 | 25 | @end 26 | 27 | -------------------------------------------------------------------------------- /STULabel/STULabelSwiftExtensions.h: -------------------------------------------------------------------------------- 1 | 2 | #import "STULabel.h" 3 | 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | STU_EXTERN_C_BEGIN 7 | 8 | NS_SWIFT_NAME(getter:STUShapedString.length(self:)) 9 | size_t STUShapedStringGetLength(STUShapedString *self); 10 | 11 | typedef struct NS_REFINED_FOR_SWIFT STUTextFrameWithOrigin { 12 | STUTextFrame * __unsafe_unretained textFrame; 13 | CGPoint origin; 14 | CGFloat displayScale; 15 | } STUTextFrameWithOrigin; 16 | 17 | STUTextFrameWithOrigin STULabelGetTextFrameWithOrigin(STULabel *label) NS_REFINED_FOR_SWIFT; 18 | 19 | STUTextFrameWithOrigin STULabelLayerGetTextFrameWithOrigin(STULabelLayer *labelLayer) 20 | NS_REFINED_FOR_SWIFT; 21 | 22 | STUTextFrameWithOrigin STULabelDrawingBlockParametersGetTextFrameWithOrigin( 23 | STULabelDrawingBlockParameters *params) NS_REFINED_FOR_SWIFT; 24 | 25 | STU_EXTERN_C_END 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /STULabel/STULayerWithNullDefaultActions.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2017 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | /// CALayer subclass with a `defaultActionForKey:` implementation that always returns `NSNull` 8 | /// in order to suppress implicit animations. 9 | STU_EXPORT 10 | @interface STULayerWithNullDefaultActions : CALayer 11 | @end 12 | 13 | /// CAShapeLayer subclass with a `defaultActionForKey:` implementation that always returns `NSNull` 14 | /// in order to suppress implicit animations. 15 | STU_EXPORT 16 | @interface STUShapeLayerWithNullDefaultActions : CAShapeLayer 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /STULabel/STULayerWithNullDefaultActions.m: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2017 Stephan Tolksdorf 2 | 3 | #import "STULayerWithNullDefaultActions.h" 4 | 5 | @implementation STULayerWithNullDefaultActions 6 | 7 | + (id)defaultActionForKey:(NSString *) __unused event { 8 | return NSNull.null; 9 | } 10 | 11 | @end 12 | 13 | @implementation STUShapeLayerWithNullDefaultActions 14 | 15 | + (id)defaultActionForKey:(NSString *) __unused event { 16 | return NSNull.null; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /STULabel/STUMainScreenProperties.h: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2018 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | STU_EXTERN_C_BEGIN 8 | 9 | typedef NS_ENUM(NSInteger, STUDisplayGamut) { 10 | STU_DISABLE_CLANG_WARNING("-Wunguarded-availability") 11 | STUDisplayGamutUnspecified = UIDisplayGamutUnspecified, 12 | STUDisplayGamutSRGB = UIDisplayGamutSRGB, 13 | STUDisplayGamutP3 = UIDisplayGamutP3 14 | STU_REENABLE_CLANG_WARNING 15 | }; 16 | 17 | /// Returns the value of @c UIScreen.main.fixedCoordinateSpace.bounds.size. 18 | /// Thread-safe. 19 | CGSize stu_mainScreenPortraitSize(void); 20 | 21 | /// Returns the value of @c UIScreen.main.scale. 22 | /// Thread-safe. 23 | CGFloat stu_mainScreenScale(void); 24 | 25 | /// Returns the value of @c UIScreen.main.traitCollection.displayGamut. 26 | /// Thread-safe. 27 | STUDisplayGamut stu_mainScreenDisplayGamut(void); 28 | 29 | STU_EXTERN_C_END 30 | -------------------------------------------------------------------------------- /STULabel/STUObjCRuntimeWrappers-no-ARC.m: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #if __has_feature(objc_arc) 4 | #error This file must be compiled with -fno-objc-arc 5 | #endif 6 | 7 | #import "STUObjCRuntimeWrappers.h" 8 | 9 | #import "stu/Assert.h" 10 | 11 | #import 12 | 13 | STU_EXPORT STU_NO_INLINE 14 | id stu_createClassInstance(Class cls, size_t extraBytes) NS_RETURNS_RETAINED { 15 | void * const instance = class_createInstance(cls, extraBytes); 16 | STU_CHECK_MSG(instance != nil, "Failed to allocate class instance."); 17 | return instance; 18 | } 19 | 20 | STU_EXPORT STU_NO_INLINE 21 | id stu_constructClassInstance(Class cls, void *storage) NS_RETURNS_RETAINED { 22 | const id instance = objc_constructInstance(cls, storage); 23 | STU_CHECK_MSG(instance != nil, "Failed to construct class instance."); 24 | return instance; 25 | } 26 | 27 | STU_EXPORT 28 | void *stu_getObjectIndexedIvars(id object) { 29 | return object_getIndexedIvars(object); 30 | } 31 | -------------------------------------------------------------------------------- /STULabel/STUObjCRuntimeWrappers.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | STU_EXTERN_C_BEGIN 10 | 11 | /// A simple wrapper of @c class_createInstance callable from ARC code. 12 | id stu_createClassInstance(Class cls, size_t extraBytes) NS_RETURNS_RETAINED; 13 | 14 | /// A simple wrapper of @c objc_constructInstance callable from ARC code. 15 | id stu_constructClassInstance(Class cls, void *storage) NS_RETURNS_RETAINED; 16 | 17 | /// A simple wrapper of @c object_getIndexedIvars callable from ARC code. 18 | void *stu_getObjectIndexedIvars(id object); 19 | 20 | STU_EXTERN_C_END 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /STULabel/STUParagraphStyle-Internal.hpp: -------------------------------------------------------------------------------- 1 | #import "STUParagraphStyle.h" 2 | 3 | namespace stu_label { 4 | 5 | struct ParagraphExtraStyle { 6 | STUFirstLineOffsetType firstLineOffsetType; 7 | CGFloat firstLineOffset; 8 | CGFloat minimumBaselineDistance; 9 | NSInteger numberOfInitialLines; 10 | CGFloat initialLinesHeadIndent; 11 | CGFloat initialLinesTailIndent; 12 | }; 13 | 14 | } 15 | 16 | @interface STUParagraphStyle () { 17 | @package 18 | stu_label::ParagraphExtraStyle _style; 19 | } 20 | @end 21 | 22 | 23 | -------------------------------------------------------------------------------- /STULabel/STUShapedString-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUShapedString.h" 4 | 5 | #import "Internal/Unretained.hpp" 6 | 7 | namespace stu_label { 8 | class ShapedString; 9 | Unretained emptyShapedString(STUWritingDirection); 10 | } 11 | 12 | STU_EXTERN_C_BEGIN 13 | 14 | @interface STUShapedString () { 15 | @package 16 | const stu_label::ShapedString* const shapedString; 17 | } 18 | @end 19 | 20 | STUShapedString* __nullable STUShapedStringCreate(__nullable Class cls, 21 | NSAttributedString* __nonnull, 22 | STUWritingDirection, 23 | const STUCancellationFlag* __nullable) 24 | NS_RETURNS_RETAINED; 25 | 26 | NSAttributedString* __nonnull stu_emptyAttributedString(); 27 | 28 | STU_EXTERN_C_END 29 | 30 | -------------------------------------------------------------------------------- /STULabel/STUStartEndRange-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STUStartEndRange.h" 4 | 5 | #import "stu/Range.hpp" 6 | 7 | template <> 8 | struct stu::RangeConversion { 9 | STU_CONSTEXPR 10 | static Range toRange(STUStartEndRange range) noexcept { 11 | return {range.start, range.end}; 12 | } 13 | 14 | STU_CONSTEXPR 15 | static STUStartEndRange fromRange(Range range) noexcept { 16 | return {range.start, range.end}; 17 | } 18 | }; 19 | 20 | template <> 21 | struct stu::RangeConversion { 22 | STU_CONSTEXPR 23 | static Range toRange(STUStartEndRangeI32 range) noexcept { 24 | return {range.start, range.end}; 25 | } 26 | 27 | STU_CONSTEXPR 28 | static STUStartEndRangeI32 fromRange(Range range) noexcept { 29 | return {range.start, range.end}; 30 | } 31 | }; 32 | 33 | -------------------------------------------------------------------------------- /STULabel/STUStartEndRange.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | typedef struct STUStartEndRange { 6 | CFIndex start; 7 | CFIndex end; 8 | } STUStartEndRange; 9 | 10 | typedef struct STUStartEndRangeI32 { 11 | int32_t start; 12 | int32_t end; 13 | } STUStartEndRangeI32; 14 | 15 | -------------------------------------------------------------------------------- /STULabel/STUTextAttachment-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextAttachment.h" 4 | 5 | #import "Internal/DrawingContext.hpp" 6 | 7 | @interface STUTextAttachment() { 8 | @package 9 | CGFloat _width; 10 | CGFloat _ascent; 11 | CGFloat _descent; 12 | CGFloat _leading; 13 | stu_label::FontMetrics _metrics; 14 | stu_label::Rect _imageBounds; 15 | NSString* _stringRepresentation; 16 | STUTextAttachmentColorInfo _colorInfo; 17 | } 18 | @end 19 | 20 | namespace stu_label { 21 | 22 | extern const NSAttributedStringKey fixForRDAR36622225AttributeName; 23 | 24 | void drawAttachment(const STUTextAttachment*, CGFloat xOffset, CGFloat baselineOffset, 25 | Int glyphCount, stu_label::DrawingContext& context); 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /STULabel/STUTextAttributes-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextAttributes.h" 4 | 5 | #import "STUBackgroundAttribute-Internal.h" 6 | #import "STUParagraphStyle-Internal.hpp" 7 | #import "STUTextAttachment-Internal.hpp" 8 | #import "STUTruncationScope-Internal.h" 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /STULabel/STUTextAttributes.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUBackgroundAttribute.h" 4 | #import "STUParagraphStyle.h" 5 | #import "STUTextAttachment.h" 6 | #import "STUTruncationScope.h" 7 | 8 | STU_ASSUME_NONNULL_AND_STRONG_BEGIN 9 | 10 | /// The value for this key must be an NSString with a locale identifier (in the format recognized 11 | /// by @c NSLocale). 12 | NS_SWIFT_NAME(stuHyphenationLocaleIdentifier) 13 | extern const NSAttributedStringKey STUHyphenationLocaleIdentifierAttributeName; 14 | 15 | STU_ASSUME_NONNULL_AND_STRONG_END 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /STULabel/STUTextAttributes.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextAttributes-Internal.hpp" 4 | 5 | #import "Internal/InputClamping.hpp" 6 | #import "Internal/NSCoderUtils.hpp" 7 | #import "Internal/Once.hpp" 8 | 9 | using namespace stu; 10 | using namespace stu_label; 11 | 12 | STU_EXPORT 13 | const NSAttributedStringKey STUHyphenationLocaleIdentifierAttributeName 14 | = @"STUHyphenationLocaleIdentifier"; 15 | 16 | -------------------------------------------------------------------------------- /STULabel/STUTextFlags.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | typedef NS_OPTIONS(uint16_t, STUTextFlags) { 8 | STUTextHasLink = 1 << 0, 9 | STUTextHasBackground = 1 << 1, 10 | STUTextHasShadow = 1 << 2, 11 | STUTextHasUnderline = 1 << 3, 12 | STUTextHasStrikethrough = 1 << 4, 13 | STUTextHasStroke = 1 << 5, 14 | STUTextHasAttachment = 1 << 6, 15 | STUTextHasBaselineOffset = 1 << 7, 16 | STUTextMayNotBeGrayscale = 1 << 8, 17 | STUTextUsesExtendedColor = 1 << 9, 18 | 19 | STUTextDecorationFlags = STUTextHasBackground 20 | | STUTextHasShadow 21 | | STUTextHasUnderline 22 | | STUTextHasStrikethrough 23 | | STUTextHasStroke 24 | }; 25 | 26 | enum { 27 | STUTextFlagsBitSize STU_SWIFT_UNAVAILABLE = 10 28 | }; 29 | -------------------------------------------------------------------------------- /STULabel/STUTextFrameDrawingOptions-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import "STUTextFrameDrawingOptions.h" 4 | 5 | #import "Internal/TextFrameDrawingOptions.hpp" 6 | 7 | @interface STUTextFrameDrawingOptions() { 8 | @package 9 | stu_label::TextFrameDrawingOptions impl; 10 | } 11 | @end 12 | 13 | STU_EXTERN_C_BEGIN 14 | 15 | /// @pre `other.class == STUTextFrameDrawingOptions.class` 16 | STUTextFrameDrawingOptions* 17 | STUTextFrameDrawingOptionsCopy(STUTextFrameDrawingOptions* __nullable other) NS_RETURNS_RETAINED; 18 | 19 | STU_EXTERN_C_END 20 | -------------------------------------------------------------------------------- /STULabel/STUTextFrameLine.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2018 Stephan Tolksdorf 2 | 3 | #import "Internal/TextFrame.hpp" 4 | 5 | using namespace stu; 6 | using namespace stu_label; 7 | 8 | STU_EXPORT 9 | CGFloat STUTextFrameLineGetCapHeight(const STUTextFrameLine* __nonnull line) { 10 | return down_cast(line)->maxFontMetricValue(); 11 | } 12 | 13 | STU_EXPORT 14 | CGFloat STUTextFrameLineGetXHeight(const STUTextFrameLine* __nonnull line) { 15 | return down_cast(line)->maxFontMetricValue(); 16 | } 17 | 18 | STU_EXPORT 19 | STUTextFrameGraphemeClusterRange STUTextFrameLineGetRangeOfGraphemeClusterAtXOffset( 20 | const STUTextFrameLine* __nonnull line, Float64 xOffset) 21 | { 22 | STU_CHECK_MSG(0 <= xOffset, "xOffset must be non-negative"); 23 | STU_CHECK_MSG(xOffset <= line->width, "xOffset must not be greater than line.width"); 24 | ThreadLocalArenaAllocator::InitialBuffer<2048> buffer; 25 | ThreadLocalArenaAllocator alloc{Ref{buffer}}; 26 | return narrow_cast( 27 | down_cast(line)->rangeOfGraphemeClusterAtXOffset(xOffset)); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /STULabel/STUTextHighlightStyle-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextHighlightStyle.h" 4 | 5 | #import "Internal/TextStyle.hpp" 6 | 7 | namespace stu_label { 8 | 9 | struct TextHighlightStyle { 10 | struct Info { 11 | TextStyle::BackgroundInfo background; 12 | TextStyle::ShadowInfo shadow; 13 | TextStyle::UnderlineInfo underline; 14 | TextStyle::StrikethroughInfo strikethrough; 15 | TextStyle::StrokeInfo stroke; 16 | }; 17 | 18 | using ColorArray = Color[stu_label::ColorIndex::highlightColorCount]; 19 | 20 | TextFlags flagsMask; 21 | TextFlags flags; 22 | Optional textColorIndex; 23 | ColorArray colors; 24 | Info info; 25 | }; 26 | 27 | } // namespace stu_label 28 | 29 | @interface STUTextHighlightStyle() { 30 | @package 31 | stu_label::TextHighlightStyle style; 32 | } 33 | @end 34 | 35 | -------------------------------------------------------------------------------- /STULabel/STUTextLink-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextLink.h" 4 | 5 | #import "Internal/Common.hpp" 6 | #import "Internal/Unretained.hpp" 7 | 8 | namespace stu_label { 9 | struct TextFrame; 10 | class TextFrameScaleAndDisplayScale; 11 | 12 | stu_label::Unretained emptySTUTextLinkArray(); 13 | 14 | Optional indexOfMatchingLink(NSArray*, STUTextLink*); 15 | } 16 | 17 | @interface STUTextLinkArrayWithTextFrameOrigin : STUTextLinkArray 18 | @end 19 | 20 | NS_ASSUME_NONNULL_BEGIN 21 | 22 | STUTextLinkArrayWithTextFrameOrigin* 23 | STUTextLinkArrayCreateWithTextFrameOriginAndDisplayScale( 24 | const stu_label::TextFrame& textFrame, CGPoint textFrameOrigin, 25 | const stu_label::TextFrameScaleAndDisplayScale& scaleFactors) 26 | NS_RETURNS_RETAINED; 27 | 28 | STU_EXTERN_C_BEGIN 29 | 30 | CGPoint STUTextLinkArrayGetTextFrameOrigin(const STUTextLinkArrayWithTextFrameOrigin* self); 31 | 32 | STUTextLinkArrayWithTextFrameOrigin* 33 | STUTextLinkArrayCopyWithShiftedTextFrameOrigin( 34 | const STUTextLinkArrayWithTextFrameOrigin* self, CGPoint textFrameOrigin) 35 | NS_RETURNS_RETAINED; 36 | 37 | STU_EXTERN_C_END 38 | 39 | NS_ASSUME_NONNULL_END 40 | -------------------------------------------------------------------------------- /STULabel/STUTextRange.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | typedef NS_ENUM(uint8_t, STUTextRangeType) { 6 | STURangeInOriginalString = 0, 7 | STURangeInTruncatedString = 1 8 | }; 9 | enum { STUTextRangeTypeBitSize STU_SWIFT_UNAVAILABLE = 1 }; 10 | 11 | typedef struct STUTextRange { 12 | NSRange range; 13 | STUTextRangeType type; 14 | } STUTextRange; 15 | 16 | -------------------------------------------------------------------------------- /STULabel/STUTextRectArray-Internal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTextRectArray.h" 4 | 5 | #import "Internal/DisplayScaleRounding.hpp" 6 | #import "Internal/TextFrame.hpp" 7 | #import "Internal/TextLineSpan.hpp" 8 | 9 | STUTextRectArray* __nonnull STUTextRectArrayCreate( 10 | __nullable Class cls, 11 | stu::ArrayRef, 12 | stu::ArrayRef, 13 | stu_label::TextFrameOrigin, 14 | const stu_label::TextFrameScaleAndDisplayScale&) 15 | NS_RETURNS_RETAINED; 16 | 17 | /// \pre `array` must have been created with `STUTextRectArrayCreate` 18 | STUTextRectArray* __nonnull STUTextRectArrayCopyWithOffset( 19 | __nonnull Class cls, const STUTextRectArray* array, CGPoint offset) 20 | NS_RETURNS_RETAINED; 21 | 22 | stu_label::Rect STUTextRectArrayGetBounds(STUTextRectArray*); 23 | 24 | STUIndexAndDistance STUTextRectArrayFindRectClosestToPoint( 25 | const STUTextRectArray* self, CGPoint point, CGFloat maxDistance); 26 | 27 | -------------------------------------------------------------------------------- /STULabel/STUTruncationScope-Internal.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUTruncationScope.h" 4 | 5 | @interface STUTruncationScope () { 6 | @package 7 | NSRange _truncatableStringRange; 8 | int32_t _maximumNumberOfLines; 9 | CTLineTruncationType _lastLineTruncationMode; 10 | NSAttributedString* __nullable _truncationToken; 11 | NSAttributedString* __nullable _fixedTruncationToken; 12 | } 13 | @end 14 | -------------------------------------------------------------------------------- /STULabel/STUTruncationScope.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "STUDefines.h" 4 | 5 | #import 6 | 7 | #import 8 | 9 | STU_ASSUME_NONNULL_AND_STRONG_BEGIN 10 | 11 | NS_SWIFT_NAME(stuTruncationScope) 12 | extern const NSAttributedStringKey STUTruncationScopeAttributeName; 13 | 14 | /// A paragraph-level attribute that establishes a separate truncation scope for the attributed 15 | /// paragraph(s). 16 | /// 17 | /// Equality for @c STUTruncationScope instances is defined as pointer equality. 18 | STU_EXPORT 19 | @interface STUTruncationScope : NSObject 20 | 21 | - (instancetype)initWithMaximumNumberOfLines:(int32_t)maximumNumberOfLines; 22 | 23 | - (instancetype)initWithMaximumNumberOfLines:(int32_t)maximumNumberOfLines 24 | lastLineTruncationMode:(CTLineTruncationType)lastLineTruncationMode 25 | truncationToken:(NSAttributedString * __nullable)truncationToken; 26 | 27 | - (instancetype)initWithMaximumNumberOfLines:(int32_t)maximumNumberOfLines 28 | lastLineTruncationMode:(CTLineTruncationType)lastLineTruncationMode 29 | truncationToken:(NSAttributedString * __nullable)truncationToken 30 | truncatableStringRange:(NSRange)stringRange 31 | NS_DESIGNATED_INITIALIZER; 32 | 33 | - (nullable instancetype)initWithCoder:(NSCoder *)decoder 34 | NS_DESIGNATED_INITIALIZER; 35 | 36 | @property (readonly) int32_t maximumNumberOfLines; 37 | 38 | @property (readonly) CTLineTruncationType lastLineTruncationMode; 39 | 40 | @property (readonly, nullable) NSAttributedString *truncationToken; 41 | 42 | @property (readonly) NSRange truncatableStringRange; 43 | 44 | @end 45 | 46 | STU_ASSUME_NONNULL_AND_STRONG_END 47 | -------------------------------------------------------------------------------- /STULabel/UIFont+STUDynamicTypeFontScaling.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | NS_ASSUME_NONNULL_BEGIN 6 | 7 | @interface UIFont (STUDynamicTypeScaling) 8 | 9 | - (UIFont *)stu_fontAdjustedForContentSizeCategory:(UIContentSizeCategory)category 10 | API_AVAILABLE(ios(10.0), tvos(10.0)); 11 | 12 | @end 13 | 14 | NS_ASSUME_NONNULL_END 15 | -------------------------------------------------------------------------------- /STULabel/stu_mutex.c: -------------------------------------------------------------------------------- 1 | // Copyright 2016–2018 Stephan Tolksdorf 2 | 3 | #include "stu_mutex.h" 4 | 5 | STU_DISABLE_CLANG_WARNING("-Wunguarded-availability") 6 | STU_DISABLE_CLANG_WARNING("-Wunreachable-code") 7 | 8 | #if !STU_ALWAYS_HAS_OS_LOCK 9 | 10 | STU_EXPORT STU_NO_INLINE 11 | void stu_mutex_destroy(stu_mutex * __nonnull mutex) { 12 | if (&os_unfair_lock_lock) return; 13 | pthread_mutex_destroy(&mutex->pthread_mutex); 14 | } 15 | 16 | STU_EXPORT STU_NO_INLINE 17 | bool stu_mutex_trylock(stu_mutex * __nonnull mutex) { 18 | if (&os_unfair_lock_trylock) { 19 | return os_unfair_lock_trylock(&mutex->unfair_lock); 20 | } 21 | return pthread_mutex_trylock(&mutex->pthread_mutex) == 0; 22 | } 23 | 24 | STU_EXPORT STU_NO_INLINE 25 | void stu_mutex_lock(stu_mutex * __nonnull mutex) { 26 | if (&os_unfair_lock_lock) { 27 | os_unfair_lock_lock(&mutex->unfair_lock); 28 | return; 29 | } 30 | pthread_mutex_lock(&mutex->pthread_mutex); 31 | } 32 | 33 | STU_EXPORT STU_NO_INLINE 34 | void stu_mutex_unlock(stu_mutex * __nonnull mutex) { 35 | if (&os_unfair_lock_unlock) { 36 | os_unfair_lock_unlock(&mutex->unfair_lock); 37 | return; 38 | } 39 | pthread_mutex_unlock(&mutex->pthread_mutex); 40 | } 41 | 42 | #endif // STU_ALWAYS_HAS_OS_LOCK 43 | 44 | STU_REENABLE_CLANG_WARNING 45 | STU_REENABLE_CLANG_WARNING 46 | -------------------------------------------------------------------------------- /STULabelSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'STULabelSwift' 3 | s.version = '0.8.11' 4 | s.dependency 'STULabel', "~> 0.8.11" 5 | 6 | s.swift_version = '5.0' 7 | s.platform = :ios, '9.3' 8 | 9 | s.license = { :type => '2-clause BSD', :file => 'LICENSE.txt' } 10 | 11 | s.homepage = 'https://github.com/stephan-tolksdorf/STULabel' 12 | s.source = { :git => 'https://github.com/stephan-tolksdorf/STULabel.git', :tag => "#{s.version}" } 13 | s.author = { 'Stephan Tolksdorf' => 'stulabel@quanttec.com' } 14 | s.social_media_url = 'https://twitter.com/s_tolksdorf' 15 | 16 | s.summary = 'A faster and more flexible label view for iOS' 17 | 18 | s.source_files = 'STULabelSwift/**/*.swift' 19 | 20 | s.prefix_header_file = false 21 | 22 | s.pod_target_xcconfig = { 23 | 'SWIFT_INSTALL_OBJC_HEADER' => 'NO' 24 | } 25 | end 26 | -------------------------------------------------------------------------------- /STULabelSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /STULabelSwift/Internal/RoundToScale.swift: -------------------------------------------------------------------------------- 1 | 2 | import CoreGraphics 3 | 4 | @inlinable 5 | internal func roundToScale(_ value: F, _ scale: F) -> F { 6 | guard scale > 0 else { return value } 7 | return (value*scale).rounded(.toNearestOrEven)/scale 8 | } 9 | 10 | @inlinable 11 | internal func ceilToScale(_ value: F, _ scale: F) -> F { 12 | guard scale > 0 else { return value } 13 | let scaledValue = value*scale; 14 | let roundedValue = scaledValue.rounded(.toNearestOrEven)/scale 15 | let ceiledValue = scaledValue.rounded(.up)/scale 16 | let maxRelDiff = (MemoryLayout.size <= 4 ? 32 : 128) * F.ulpOfOne 17 | return abs(roundedValue - value) <= abs(value)*maxRelDiff 18 | ? roundedValue : ceiledValue; 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /STULabelSwift/STULabel.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STULabel { 6 | @inlinable 7 | public var textFrame: STUTextFrameWithOrigin { 8 | return STUTextFrameWithOrigin(__STULabelGetTextFrameWithOrigin(self)) 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /STULabelSwift/STULabelDrawingBlockParameters.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STULabelDrawingBlockParameters { 6 | @inlinable 7 | public var textFrame: STUTextFrameWithOrigin { 8 | return STUTextFrameWithOrigin(__STULabelDrawingBlockParametersGetTextFrameWithOrigin(self)) 9 | } 10 | 11 | @inlinable 12 | public var range: Range { return Range(__range) } 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /STULabelSwift/STULabelLayer.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STULabelLayer { 6 | @inlinable 7 | public var textFrame: STUTextFrameWithOrigin { 8 | return STUTextFrameWithOrigin(__STULabelLayerGetTextFrameWithOrigin(self)) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /STULabelSwift/STUStartEndRange.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STUStartEndRange { 6 | @inlinable 7 | public var nsRange: NSRange { 8 | return NSRange(location: start, length: end &- start) 9 | } 10 | } 11 | 12 | extension STUStartEndRangeI32 { 13 | @inlinable 14 | public var nsRange: NSRange { 15 | return NSRange(location: Int(start), length: Int(end) &- Int(start)) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /STULabelSwift/STUTextFrameDrawingOptions.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STUTextFrame.DrawingOptions { 6 | 7 | /// Sets the specified STUTextFrameRange as the highlight range. 8 | /// 9 | /// - note: A `STUTextFrameDrawingOptions` instance with a `STUTextFrameRange` highlight range 10 | /// must only be used together with `STUTextFrame` instances for which the range is valid. 11 | /// - postcondition: `highlightTextFrameRange == textFrameRange` 12 | @inlinable 13 | public func setHighlightRange(_ textFrameRange: Range) { 14 | __setHighlightRange(__STUTextFrameRange(textFrameRange)) 15 | } 16 | 17 | @inlinable 18 | public var highlightTextFrameRange: Optional> { 19 | var range = __STUTextFrameRange() 20 | if __getHighlightTextFrameRange(&range) { 21 | return Range(range) 22 | } 23 | return nil 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /STULabelSwift/STUTextRectArray.overlay.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @_exported import STULabel 4 | 5 | extension STUTextRectArray { 6 | 7 | /// Returns the index and distance of the rect closest to the specified point. 8 | /// In case of a tie the index of the first rect with the minimum distance is returned. 9 | /// 10 | /// If the array contains no rect or if the distance between the closest rect and the point is 11 | /// greater than `maxDistance`, this method returns nil. 12 | @inlinable 13 | public func findRect(closestTo point: CGPoint, maxDistance: CGFloat) 14 | -> (index: Int, distance: CGFloat)? 15 | { 16 | let r = self.__findRectClosest(to: point, maxDistance: maxDistance) 17 | if r.index != NSNotFound { 18 | return (index: r.index, r.distance) 19 | } 20 | return nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_2.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_20.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_2_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_2_32bit.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_5.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_h5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_h5.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_inset_v5.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_2.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_20.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_2_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_2_32bit.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_outset_5.png -------------------------------------------------------------------------------- /Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_shifted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/Internal/ReferenceImages/TextLineSpansPathTests/testAddLineSpansPath_1_rounded_shifted.png -------------------------------------------------------------------------------- /Tests/Internal/TestUtils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #import 4 | 5 | #import "stu/Assert.h" 6 | 7 | #import "stdatomic.h" 8 | 9 | extern _Atomic(bool) stu_assertion_test; 10 | 11 | #define CHECK_FAILS_ASSERT(expr) \ 12 | { \ 13 | atomic_store_explicit(&stu_assertion_test, true, memory_order_relaxed); \ 14 | XCTAssertThrows(expr); \ 15 | atomic_store_explicit(&stu_assertion_test, false, memory_order_relaxed); \ 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Tests/Internal/stu/AllocationTests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/Allocation.hpp" 4 | 5 | #include "TestUtils.hpp" 6 | 7 | #include "AllocatorUtils.hpp" 8 | 9 | using namespace stu; 10 | 11 | TEST_CASE_START(AllocationTests) 12 | 13 | #if STU_ASSERT_MAY_THROW 14 | TEST(AllocatorBasePreconditionAssert) { 15 | ValidatingMalloc allocator; 16 | #if !STU_NO_EXCEPTIONS 17 | CHECK_THROWS_BAD_ALLOC(allocator.allocate(maxValue/2 + 1)); 18 | CHECK_THROWS_BAD_ALLOC(allocator.allocate(maxValue/2 + 1)); 19 | #endif 20 | UInt* p = allocator.allocate(2); 21 | #if !STU_NO_EXCEPTIONS 22 | CHECK_THROWS_BAD_ALLOC(allocator.increaseCapacity(p, UInt{0}, UInt{2}, UInt{maxValue} + 1)); 23 | #endif 24 | CHECK_FAILS_ASSERT(allocator.increaseCapacity(p, 0, 2, 1)); 25 | CHECK_FAILS_ASSERT(allocator.increaseCapacity(p, 3, 2, 2)); 26 | CHECK_FAILS_ASSERT(allocator.decreaseCapacity(p, 2, 2, 3)); 27 | CHECK_FAILS_ASSERT(allocator.decreaseCapacity(p, 3, 2, 2)); 28 | allocator.deallocate(p, 2); 29 | } 30 | #endif 31 | 32 | TEST(Malloc) { 33 | static_assert(isAllocator); 34 | static_assert(isAllocatorRef); 35 | ValidatingMalloc allocator; 36 | Int* p = allocator.allocate(1); 37 | *p = 1; 38 | allocator.deallocate(p); 39 | p = allocator.allocate(2); 40 | p[0] = 1; 41 | p[1] = 2; 42 | p = allocator.decreaseCapacity(p, 1, 2, 1); 43 | CHECK_EQ(p[0], 1); 44 | p = allocator.increaseCapacity(p, 1, 1, 2); 45 | CHECK_EQ(p[0], 1); 46 | p[1] = 2; 47 | p = allocator.increaseCapacity(p, 2, 2, 3); 48 | CHECK_EQ(p[0], 1); 49 | CHECK_EQ(p[1], 2); 50 | p[2] = 3; 51 | p = allocator.decreaseCapacity(p, 0, 3, 0); 52 | CHECK(p != nullptr); 53 | allocator.deallocate(p, 0); 54 | p = allocator.allocate(0); 55 | CHECK(p != nullptr); 56 | allocator.deallocate(p, 0); 57 | } 58 | 59 | TEST_CASE_END 60 | -------------------------------------------------------------------------------- /Tests/Internal/stu/AllocatorUtils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "AllocatorUtils.hpp" 4 | 5 | STU_DISABLE_CLANG_WARNING("-Wexit-time-destructors") 6 | 7 | MoveOnlyAllocatorRef::Allocator MoveOnlyAllocatorRef::Allocator::instance{}; 8 | 9 | STU_REENABLE_CLANG_WARNING 10 | 11 | -------------------------------------------------------------------------------- /Tests/Internal/stu/BinarySearchTests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/BinarySearch.hpp" 4 | 5 | #include "stu/Vector.hpp" 6 | 7 | #include "TestUtils.hpp" 8 | 9 | using namespace stu; 10 | 11 | TEST_CASE_START(BinarySearchTests) 12 | 13 | TEST(BinarySearch) { 14 | for (int i = 0; i < 256; ++i) { 15 | Vector vector; 16 | for (int j = 0; j < 8; ++j) { 17 | if ((i >> j) & 1) { 18 | vector.append(j); 19 | } 20 | } 21 | for (int j = -1; j < 10; ++j) { 22 | const auto predicate = [j](Int x) { return x >= j; }; 23 | const Int expected = vector.indexWhere(predicate).value_or(vector.count()); 24 | const auto result = binarySearchFirstIndexWhere(vector, predicate); 25 | CHECK_EQ(result.arrayCount, vector.count()); 26 | CHECK_EQ(result.indexOrArrayCount, expected); 27 | CHECK_EQ(result.indexIsArrayCount(), result.indexOrArrayCount == result.arrayCount); 28 | } 29 | } 30 | } 31 | 32 | TEST_CASE_END 33 | -------------------------------------------------------------------------------- /Tests/Internal/stu/FunctionRefTests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/FunctionRef.hpp" 4 | 5 | #include "TestUtils.hpp" 6 | 7 | using namespace stu; 8 | 9 | TEST_CASE_START(FunctionRefTests) 10 | 11 | static Int add3(Int value) { 12 | return value + 3; 13 | } 14 | 15 | static Int add4_noexcept(Int value) noexcept { 16 | return value + 4; 17 | } 18 | 19 | class Add { 20 | Int addend_; 21 | public: 22 | explicit Add(Int addend) 23 | : addend_{addend} {} 24 | 25 | Int operator()(Int value) const noexcept { return addend_ + value; } 26 | }; 27 | 28 | TEST(Basics) { 29 | static_assert(!isDefaultConstructible>); 30 | { 31 | FunctionRef f = add3; 32 | static_assert(!noexcept(f(1))); 33 | CHECK_EQ(f(2), 5); 34 | f = add4_noexcept; 35 | CHECK_EQ(f(2), 6); 36 | static_assert(!isAssignable&, Add>); 37 | } 38 | { 39 | const FunctionRef f = add4_noexcept; 40 | static_assert(noexcept(f(1))); 41 | CHECK_EQ(f(2), 6); 42 | static_assert(!isAssignable&, FunctionRef>); 43 | } 44 | { 45 | static_assert(isSame>); 46 | const auto result = FunctionRef{Add{5}}(-1); 47 | CHECK_EQ(result, 4); 48 | } 49 | #if STU_ASSERT_MAY_THROW 50 | CHECK_FAILS_ASSERT(FunctionRef{static_cast(nullptr)}); 51 | #endif 52 | } 53 | 54 | TEST(OptionalFunctionrRef) { 55 | Optional> opt; 56 | CHECK(!opt); 57 | CHECK(opt == none); 58 | CHECK(!(opt != none)); 59 | CHECK(none == opt); 60 | CHECK(!(none != opt)); 61 | opt = add3; 62 | CHECK_EQ(opt(1), 4); 63 | CHECK_EQ(FunctionRef(opt)(2), 5); 64 | opt = none; 65 | #if !STU_NO_EXCEPTIONS 66 | CHECK_THROWS(*opt, stu::BadOptionalAccess); 67 | CHECK_THROWS(opt(1), std::bad_function_call); 68 | #endif 69 | #if STU_ASSERT_MAY_THROW 70 | CHECK_FAILS_ASSERT(FunctionRef(opt)); 71 | #endif 72 | } 73 | 74 | TEST_CASE_END 75 | -------------------------------------------------------------------------------- /Tests/Internal/stu/NSFoundationSupportTests-no-ARC.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/NSFoundationSupport.hpp" 4 | 5 | #include "TestUtils.hpp" 6 | 7 | #if __has_feature(objc_arc) 8 | #error This file should be compiled with -fno-objc-arc 9 | #endif 10 | 11 | using namespace stu; 12 | 13 | TEST_CASE_START(NSFoundationSupportNoARCTests) 14 | 15 | TEST(RefCountTraits) { 16 | static_assert(isRefCountable>); 17 | static_assert(isRefCountable); 18 | const CFArrayRef obj = CFArrayCreateMutable(nullptr, 1, nullptr); 19 | XCTAssertEqual(CFGetRetainCount(obj), 1); 20 | incrementRefCount(obj); 21 | XCTAssertEqual(CFGetRetainCount(obj), 2); 22 | decrementRefCount(obj); 23 | XCTAssertEqual(CFGetRetainCount(obj), 1); 24 | incrementRefCount((NSArray*)obj); 25 | XCTAssertEqual(CFGetRetainCount(obj), 2); 26 | decrementRefCount((NSArray*)obj); 27 | XCTAssertEqual(CFGetRetainCount(obj), 1); 28 | decrementRefCount(obj); 29 | } 30 | 31 | TEST_CASE_END 32 | -------------------------------------------------------------------------------- /Tests/Internal/stu/NSFoundationSupportTests.mm: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/NSFoundationSupport.hpp" 4 | 5 | #include "Equal.hpp" 6 | 7 | #include "TestUtils.hpp" 8 | 9 | using namespace stu; 10 | 11 | TEST_CASE_START(NSFoundationSupportTests) 12 | 13 | TEST(TypeTraits) { 14 | static_assert(isBridgableToId); 15 | static_assert(!isBridgableToId); 16 | static_assert(isConvertible); 17 | static_assert(isBlock); 18 | static_assert(isConvertible); 19 | } 20 | 21 | TEST(RefCountTraits) { 22 | static_assert(isRefCountable>); 23 | static_assert(isRefCountable); 24 | const CFArrayRef obj = CFArrayCreateMutable(nullptr, 1, nullptr); 25 | XCTAssertEqual(CFGetRetainCount(obj), 1); 26 | incrementRefCount(obj); 27 | XCTAssertEqual(CFGetRetainCount(obj), 2); 28 | decrementRefCount(obj); 29 | XCTAssertEqual(CFGetRetainCount(obj), 1); 30 | incrementRefCount((__bridge NSArray*)obj); 31 | XCTAssertEqual(CFGetRetainCount(obj), 2); 32 | decrementRefCount((__bridge NSArray*)obj); 33 | XCTAssertEqual(CFGetRetainCount(obj), 1); 34 | decrementRefCount(obj); 35 | } 36 | 37 | TEST(RangeConversion) { 38 | XCTAssertEqual(Range(NSRange{.location = 1, .length = 2}), Range(1, 3)); 39 | { 40 | const auto range = NSRange(Range(1, 3)); 41 | XCTAssertEqual(range.location, 1); 42 | XCTAssertEqual(range.length, 2); 43 | } 44 | XCTAssertEqual(Range(CFRange{.location = 1, .length = 2}), Range(1, 3)); 45 | { 46 | const auto range = CFRange(Range(1, 3)); 47 | XCTAssertEqual(range.location, 1); 48 | XCTAssertEqual(range.length, 2); 49 | } 50 | } 51 | 52 | 53 | TEST_CASE_END 54 | -------------------------------------------------------------------------------- /Tests/Internal/stu/RangeTests.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "stu/Range.hpp" 4 | 5 | #include "TestUtils.hpp" 6 | 7 | using namespace stu; 8 | 9 | TEST_CASE_START(RangeTests) 10 | 11 | TEST(Range) { 12 | { 13 | Range r{1, 2}; 14 | r += 1; 15 | CHECK_EQ(r, Range(2, 3)); 16 | } 17 | CHECK_EQ(Range(1, 2) + 1, Range(2, 3)); 18 | CHECK_EQ(Range(1, 2) + 1LL, Range(2, 3)); 19 | CHECK_EQ(1 + Range(1, 2), Range(2, 3)); 20 | CHECK_EQ(1LL + Range(1, 2), Range(2, 3)); 21 | 22 | { 23 | Range r{1, 2}; 24 | r -= 1; 25 | CHECK_EQ(r, Range(0, 1)); 26 | } 27 | CHECK_EQ(Range(1, 2) - 1, Range(0, 1)); 28 | CHECK_EQ(Range(1, 2) - 1LL, Range(0, 1)); 29 | 30 | { 31 | Range r{1, 2}; 32 | r *= 2; 33 | CHECK_EQ(r, Range(2, 4)); 34 | } 35 | CHECK_EQ(Range(1, 2) * 2, Range(2, 4)); 36 | CHECK_EQ(Range(1, 2) * 2LL, Range(2, 4)); 37 | CHECK_EQ(2 * Range(1, 2), Range(2, 4)); 38 | CHECK_EQ(2LL * Range(1, 2), Range(2, 4)); 39 | 40 | { 41 | Range r{1, 2}; 42 | r *= -2; 43 | CHECK_EQ(r, Range(-4, -2)); 44 | } 45 | CHECK_EQ(Range(1, 2) * -2, Range(-4, -2)); 46 | CHECK_EQ(Range(1, 2) * -2LL, Range(-4, -2)); 47 | CHECK_EQ(-2 * Range(1, 2), Range(-4, -2)); 48 | CHECK_EQ(-2LL * Range(1, 2), Range(-4, -2)); 49 | 50 | { 51 | Range r{1, 2}; 52 | r /= 2; 53 | CHECK_EQ(r, Range(0, 1)); 54 | } 55 | CHECK_EQ(Range(1, 2) / 2, Range(0, 1)); 56 | CHECK_EQ(Range(1, 2) / 2LL, Range(0, 1)); 57 | 58 | { 59 | Range r{1, 2}; 60 | r /= -2; 61 | CHECK_EQ(r, Range(-1, 0)); 62 | } 63 | CHECK_EQ(Range(1, 2) / -2, Range(-1, 0)); 64 | CHECK_EQ(Range(1, 2) / -2LL, Range(-1, 0)); 65 | } 66 | 67 | 68 | TEST_CASE_END 69 | 70 | -------------------------------------------------------------------------------- /Tests/Internal/stu/TestUtils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #pragma once 4 | 5 | #import 6 | 7 | #import 8 | 9 | #define TEST_CASE_START(name) \ 10 | @interface stu_##name : XCTestCase \ 11 | @end \ 12 | @implementation stu_##name \ 13 | - (void)setUp { \ 14 | [super setUp]; \ 15 | self.continueAfterFailure = false; \ 16 | } 17 | 18 | #define TEST_CASE_END @end 19 | 20 | #define TEST(name) - (void)test##name 21 | 22 | #define CHECK(expr) XCTAssertTrue(expr) 23 | 24 | #define CHECK_EQ(a, b) XCTAssertEqual(a, b) 25 | 26 | extern _Atomic(bool) stu_assertion_test; 27 | 28 | #define CHECK_FAILS_ASSERT(expr) \ 29 | { \ 30 | atomic_store_explicit(&stu_assertion_test, true, memory_order_relaxed); \ 31 | XCTAssertThrows(expr); \ 32 | atomic_store_explicit(&stu_assertion_test, false, memory_order_relaxed); \ 33 | } 34 | 35 | #define CHECK_THROWS_BAD_ALLOC(expr) \ 36 | try { \ 37 | (void)(expr); \ 38 | CHECK(false && "expression did not throw std::bad_alloc"); \ 39 | } catch (const std::bad_alloc&) {} 40 | 41 | #define CHECK_THROWS(expr, Exception) \ 42 | try { \ 43 | (void)(expr); \ 44 | CHECK(false && "expression did not throw" STU_STRINGIZE(Exception)); \ 45 | } catch (const Exception&) {} 46 | -------------------------------------------------------------------------------- /Tests/Internal/stu/TestValue.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | #include "TestValue.hpp" 4 | 5 | STU_DISABLE_CLANG_WARNING("-Wglobal-constructors") 6 | STU_DISABLE_CLANG_WARNING("-Wexit-time-destructors") 7 | std::unordered_set TestValueB::addresses; 8 | std::unordered_set TestValue::addresses; 9 | STU_REENABLE_CLANG_WARNING 10 | STU_REENABLE_CLANG_WARNING 11 | 12 | -------------------------------------------------------------------------------- /Tests/MainScreenPropertiesTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | import STULabel.MainScreenProperties 4 | 5 | import XCTest 6 | 7 | class MainScreenPropertiesTests: XCTestCase { 8 | 9 | func testMainScreenPortraitSize() { 10 | var size: CGSize? 11 | let item = DispatchWorkItem(block: { size = stu_mainScreenPortraitSize() }) 12 | DispatchQueue.global(qos: .default).async(execute: item) 13 | item.wait() 14 | XCTAssertEqual(size, UIScreen.main.fixedCoordinateSpace.bounds.size); 15 | } 16 | 17 | func testMainScreenScale() { 18 | var scale: CGFloat? 19 | let item = DispatchWorkItem(block: { scale = stu_mainScreenScale() }) 20 | DispatchQueue.global(qos: .default).async(execute: item) 21 | item.wait() 22 | XCTAssertEqual(scale, UIScreen.main.scale); 23 | } 24 | 25 | func testMainScreenDisplayGamut() { if #available(iOS 10, tvOS 10, *) { 26 | var gamut: STUDisplayGamut? 27 | let item = DispatchWorkItem(block: { gamut = stu_mainScreenDisplayGamut() }) 28 | DispatchQueue.global(qos: .default).async(execute: item) 29 | item.wait() 30 | XCTAssertEqual(gamut, 31 | STUDisplayGamut(rawValue: UIScreen.main.traitCollection.displayGamut.rawValue)); 32 | } } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Tests/MutexTests.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | @import STULabel.Mutex; 4 | 5 | @import XCTest; 6 | 7 | 8 | @interface MutexTests : XCTestCase 9 | 10 | @end 11 | 12 | @implementation MutexTests 13 | 14 | - (void)testInitializer { 15 | stu_mutex mutex = STU_MUTEX_INIT; 16 | stu_mutex mutex2; 17 | stu_mutex_init(&mutex2); 18 | XCTAssertTrue(memcmp(&mutex, &mutex2, sizeof(mutex)) == 0); 19 | #if !STU_ALWAYS_HAS_OS_LOCK 20 | pthread_mutex_t phtread_mutex = PTHREAD_MUTEX_INITIALIZER; 21 | XCTAssertTrue(memcmp(&mutex.pthread_mutex, &phtread_mutex, sizeof(phtread_mutex)) == 0); 22 | #endif 23 | STU_DISABLE_CLANG_WARNING("-Wunguarded-availability") 24 | os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT; 25 | XCTAssertTrue(memcmp(&mutex.unfair_lock, &unfair_lock, sizeof(unfair_lock)) == 0); 26 | STU_REENABLE_CLANG_WARNING 27 | } 28 | 29 | - (void)testLocking { 30 | stu_mutex mutex = STU_MUTEX_INIT; 31 | XCTAssertTrue(stu_mutex_trylock(&mutex)); 32 | XCTAssertTrue(!stu_mutex_trylock(&mutex)); 33 | stu_mutex_unlock(&mutex); 34 | XCTAssertTrue(stu_mutex_trylock(&mutex)); 35 | XCTAssertTrue(!stu_mutex_trylock(&mutex)); 36 | stu_mutex_unlock(&mutex); 37 | stu_mutex_lock(&mutex); 38 | stu_mutex_unlock(&mutex); 39 | XCTAssertTrue(stu_mutex_trylock(&mutex)); 40 | XCTAssertTrue(!stu_mutex_trylock(&mutex)); 41 | stu_mutex_destroy(&mutex); 42 | mutex = STU_MUTEX_INIT; 43 | XCTAssertTrue(stu_mutex_trylock(&mutex)); 44 | XCTAssertTrue(!stu_mutex_trylock(&mutex)); 45 | stu_mutex_unlock(&mutex); 46 | stu_mutex_destroy(&mutex); 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@2_32bit_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@2_32bit_phone.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_first_last@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@2_32bit_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@2_32bit_phone.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_last_first@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@2_32bit_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@2_32bit_phone.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testBaselineAnchors_swapped_first_last@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_1@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testContentLayoutGuide_2@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingAboveAndBelowWithNonLabelAnchor@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_1@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_2@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_3@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_1_overlay@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_2@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@1.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@2.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/AutoLayoutTests/testSpacingConstraints_lineHeight_3@3.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_ac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_ac.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_al.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_al.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_ar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_ar.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_bc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_bl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_br.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_cr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_tr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_2_xr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_ac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_ac.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_al.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_al.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_ar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_ar.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_bc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_bl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_br.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_br.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_cr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_tr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xc.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xl.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/LabelAlignmentTests/testAlignment_xr.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testAttachmentConversion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testAttachmentConversion.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testAttachmentConversion_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testAttachmentConversion_32bit.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testAttachmentsInTruncationToken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testAttachmentsInTruncationToken.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testAttachmentsInTruncationToken_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testAttachmentsInTruncationToken_32bit.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode_iOS10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode_iOS10.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode_iOS9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextAttachmentTests/testImageAttachmentInitializerAndEncode_iOS9.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameDrawingTests/testBaseCTMHandling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameDrawingTests/testBaseCTMHandling.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameDrawingTests/testBaselineRounding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameDrawingTests/testBaselineRounding.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameDrawingTests/testBaselineRounding_scaled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameDrawingTests/testBaselineRounding_scaled.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameDrawingTests/testDrawingIntoPDFContext.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameDrawingTests/testDrawingIntoPDFContext.pdf -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_1-3-drawn_hyphen-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_1-3-drawn_hyphen-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_all-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_all-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_black-hyphen-only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testHyphenHighlighting_black-hyphen-only.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_0-4-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_0-4-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_0-4-red_iOS10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_0-4-red_iOS10.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_4-9-drawn_5-6-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_4-9-drawn_5-6-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_4-9-drawn_5-6-red_iOS10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testNonMonotonicRunHighlighting_4-9-drawn_5-6-red_iOS10.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-2-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-2-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-4-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-4-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-4-red_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-4-red_32bit.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-red_32bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_1-red_32bit.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_2-3-drawn_2-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_2-3-drawn_2-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_2-3-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testPartialLigatureHighlighting_2-3-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testRightToLeftLineHighlighting_2-4-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testRightToLeftLineHighlighting_2-4-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testRightToLeftLineHighlighting_2-6-drawn_5-6-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testRightToLeftLineHighlighting_2-6-drawn_5-6-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_0-1-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_0-1-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_2-4-drawn_4-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_2-4-drawn_4-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_4-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_4-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_5-a-drawn_7-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_5-a-drawn_7-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_all-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_all-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_d-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_d-red.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_no-highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameHighlightingTests/testTruncatedLineHighlighting_no-highlighting.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testPartialLigatureImageBounds_if_with_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testPartialLigatureImageBounds_if_with_shadow.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_differently_stroked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_differently_stroked.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_stroked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_stroked.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_unstroked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testStrokeImageBounds_LL_unstroked.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_double.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_double.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_shadow_single_thick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_shadow_single_thick.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_thick_black_blue_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameImageBoundsTests/testUnderlineImageBounds_thick_black_blue_shadow.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testHyphenInMiddleOfLeftToRightRightToLeftLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testHyphenInMiddleOfLeftToRightRightToLeftLine.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testHyphenInRightToLeftLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testHyphenInRightToLeftLine.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testJustificationWithHyphenInLeftToRightRightToLeftLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testJustificationWithHyphenInLeftToRightRightToLeftLine.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testLTRJustification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testLTRJustification.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testRTLJustification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testRTLJustification.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TextFrameLineBreakingTests/testSoftHyphen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TextFrameLineBreakingTests/testSoftHyphen.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TruncationTests/testSingleCharacterTokenFontSelection_Hoefler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TruncationTests/testSingleCharacterTokenFontSelection_Hoefler.png -------------------------------------------------------------------------------- /Tests/ReferenceImages/TruncationTests/testSingleCharacterTokenFontSelection_PingFang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stephan-tolksdorf/STULabel/13457014e29bc09509a73efe7f8dc45306b2d829/Tests/ReferenceImages/TruncationTests/testSingleCharacterTokenFontSelection_PingFang.png -------------------------------------------------------------------------------- /Tests/SnapshotTestCase.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Stephan Tolksdorf 2 | 3 | func pathRelativeToCurrentSourceDir(_ path: String, sourceFile: StaticString = #file) -> String { 4 | return (sourceFile.withUTF8Buffer { String(decoding: $0, as: UTF8.self) as NSString } 5 | .deletingLastPathComponent as NSString).appendingPathComponent(path) 6 | } 7 | 8 | extension SnapshotTestCase { 9 | @nonobjc 10 | public func checkSnapshot(of view: UIView, contentsScale: CGFloat = 0, 11 | beforeLayoutAction: (() -> ())? = nil, suffix: String? = nil, 12 | testFilePath: String = #file, testFileLine: Int = #line) 13 | { 14 | testFilePath.withCString { 15 | self.__checkSnapshot(of: view, contentsScale: contentsScale, 16 | beforeLayoutAction: beforeLayoutAction, testNameSuffix: suffix, 17 | testFilePath: $0, testFileLine: testFileLine) 18 | } 19 | } 20 | 21 | @nonobjc 22 | public func checkSnapshot(of layer: CALayer, contentsScale: CGFloat = 0, 23 | beforeLayoutAction: (() -> ())? = nil, suffix: String? = nil, 24 | testFilePath: String = #file, testFileLine: Int = #line) 25 | { 26 | testFilePath.withCString { 27 | self.__checkSnapshot(of: layer, contentsScale: contentsScale, 28 | beforeLayoutAction: beforeLayoutAction, testNameSuffix: suffix, 29 | testFilePath: $0, testFileLine: testFileLine) 30 | } 31 | } 32 | 33 | @nonobjc 34 | public func checkSnapshotImage(_ image: UIImage, suffix: String? = nil, 35 | testFilePath: String = #file, testFileLine: Int = #line, 36 | referenceImage: UIImage? = nil) 37 | { 38 | testFilePath.withCString { 39 | self.__checkSnapshotImage(image, testNameSuffix: suffix, testFilePath: $0, 40 | testFileLine: testFileLine, referenceImage: referenceImage) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Tests/Tests-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // Copyright 2017–2018 Stephan Tolksdorf 2 | 3 | #import "SnapshotTestCase.h" 4 | 5 | CF_EXTERN_C_BEGIN 6 | 7 | CGAffineTransform CGContextGetBaseCTM(CGContextRef c); 8 | void CGContextSetBaseCTM(CGContextRef c, CGAffineTransform ctm); 9 | 10 | CF_EXTERN_C_END 11 | --------------------------------------------------------------------------------