Skip to content

Commit

Permalink
Fix #53 (#55)
Browse files Browse the repository at this point in the history
* Fix paragraphSpacing did not take effect when it was negative

* Use UIGraphicsImageRenderer

* Fix warning

* Fix #53

* Bump version to 0.2.3

* Remove unnecessary header import
  • Loading branch information
wanhmr authored Aug 29, 2023
1 parent 6829d96 commit f50949b
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 140 deletions.
4 changes: 2 additions & 2 deletions Example/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PODS:
- MPITextKit (0.2.1)
- MPITextKit (0.2.3)
- YYImage (1.0.4):
- YYImage/Core (= 1.0.4)
- YYImage/Core (1.0.4)
Expand All @@ -17,7 +17,7 @@ EXTERNAL SOURCES:
:path: "../"

SPEC CHECKSUMS:
MPITextKit: c35d4de736a88802122f957791504c16ed743e9d
MPITextKit: d362b015ea6aa294cb3c77826c99cb1d744ed58f
YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54

PODFILE CHECKSUM: 9cca02461ddd01cfc6deea5304d2f3a78a0397fd
Expand Down
4 changes: 2 additions & 2 deletions Example/Pods/Local Podspecs/MPITextKit.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Example/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion MPITextKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Pod::Spec.new do |s|
s.name = 'MPITextKit'
s.version = '0.2.2'
s.version = '0.2.3'
s.summary = 'Powerful text framework for iOS to display text based on TextKit.'

# This description is used to generate tags and improve search results.
Expand Down
27 changes: 10 additions & 17 deletions Sources/MPITextAsyncLayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,27 @@
//

#import "MPITextAsyncLayer.h"
#import <stdatomic.h>
#import "MPITextSentinel.h"
#import <libkern/OSAtomic.h>
#import "MPITextGeometryHelpers.h"

/// Global display queue, used for content rendering.
static dispatch_queue_t MPITextAsyncLayerGetDisplayQueue(void) {
#define MAX_QUEUE_COUNT 8
static int32_t queueCount;
static long queueCount;
static dispatch_queue_t queues[MAX_QUEUE_COUNT];
static dispatch_once_t onceToken;
static int32_t counter = 0;
static atomic_long counter;
dispatch_once(&onceToken, ^{
queueCount = (int32_t)[NSProcessInfo processInfo].activeProcessorCount;
queueCount = (long)[NSProcessInfo processInfo].activeProcessorCount;
queueCount = queueCount < 1 ? 1 : queueCount > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : queueCount;
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
for (NSUInteger i = 0; i < queueCount; i++) {
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0);
queues[i] = dispatch_queue_create("com.mpitextkit.text.render", attr);
}
} else {
for (NSUInteger i = 0; i < queueCount; i++) {
queues[i] = dispatch_queue_create("com.mpitextkit.text.render", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(queues[i], dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
}
for (NSUInteger i = 0; i < queueCount; i++) {
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0);
queues[i] = dispatch_queue_create("com.mpitextkit.text.render", attr);
}
});
int32_t cur = OSAtomicIncrement32(&counter);
return queues[(cur) % queueCount];
long cur = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
return queues[cur % queueCount];
#undef MAX_QUEUE_COUNT
}

Expand Down Expand Up @@ -117,7 +110,7 @@ - (void)_display {
if (async) {
if (task.willDisplay) task.willDisplay(self);
MPITextSentinel *sentinel = _sentinel;
int32_t value = sentinel.value;
long value = sentinel.value;
BOOL (^isCancelled)(void) = ^BOOL(void) {
return value != sentinel.value;
};
Expand Down
6 changes: 3 additions & 3 deletions Sources/MPITextInteractionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ typedef UIView<MPITextInteractable> MPITextInteractableView;
@property (nonatomic, weak) id<MPITextInteractionManagerDelegate> delegate;

@property (nonatomic, readonly) BOOL hasActiveLink;
@property (nonatomic, readonly) NSRange activeLinkRange;
@property (nonatomic, readonly) BOOL activeInTruncation;
@property (nonatomic, readonly) NSAttributedString *attributedText;
@property (nonatomic, assign, readonly) BOOL activeInTruncation;

@property (nullable, nonatomic, copy, readonly) NSAttributedString *highlightedAttributedText;


- (instancetype)initWithInteractableView:(MPITextInteractableView *)interactableView;

@end
Expand Down
74 changes: 49 additions & 25 deletions Sources/MPITextInteractionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ @interface MPITextInteractionManager () <UIGestureRecognizerDelegate> {
@property (nonatomic, assign) MPITextSelectionGrabberType trackingGrabberType;
@property (nonatomic, assign) NSUInteger pinnedGrabberIndex;

@property (nonatomic, assign) NSRange activeLinkRange;
@property (nonatomic, assign) BOOL activeInTruncation;

@property (nullable, nonatomic, copy) NSAttributedString *highlightedAttributedText;
@property (nullable, nonatomic, copy) NSAttributedString *snapshotAttributedText;

@end

@implementation MPITextInteractionManager
Expand Down Expand Up @@ -149,14 +155,14 @@ - (void)tapLinkIfNeeded {
if (!self.hasActiveLink) {
return;
}
[self.interactableView tapLinkWithLinkRange:self.activeLinkRange forAttributedText:self.attributedText];
[self.interactableView tapLinkWithLinkRange:self.activeLinkRange forAttributedText:self.snapshotAttributedText];
}

- (void)longPressLinkIfNeeded {
if (!self.hasActiveLink) {
return;
}
[self.interactableView longPressLinkWithLinkRange:self.activeLinkRange forAttributedText:self.attributedText];
[self.interactableView longPressLinkWithLinkRange:self.activeLinkRange forAttributedText:self.snapshotAttributedText];
}

- (void)beginSelectionAtPoint:(CGPoint)point {
Expand Down Expand Up @@ -193,19 +199,19 @@ - (void)showActiveLinkIfNeeded {
}
MPITextInteractableView *interactableView = self.interactableView;

NSMutableAttributedString *highlightedLinkAttributedText = [[self.attributedText attributedSubstringFromRange:self.activeLinkRange] mutableCopy];
NSMutableAttributedString *highlightedLinkAttributedText = [[self.snapshotAttributedText attributedSubstringFromRange:self.activeLinkRange] mutableCopy];

NSDictionary<NSString *, id> *textAttributes = [interactableView highlightedLinkTextAttributesWithLinkRange:self.activeLinkRange
forAttributedText:self.attributedText];
forAttributedText:self.snapshotAttributedText];
if (textAttributes) {
[highlightedLinkAttributedText addAttributes:textAttributes range:highlightedLinkAttributedText.mpi_rangeOfAll];
}
[highlightedLinkAttributedText addAttribute:MPITextHighlightedAttributeName value:@(YES) range:highlightedLinkAttributedText.mpi_rangeOfAll];

NSMutableAttributedString *highlightedAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
NSMutableAttributedString *highlightedAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:self.snapshotAttributedText];
[highlightedAttributedText replaceCharactersInRange:self.activeLinkRange withAttributedString:highlightedLinkAttributedText];

_highlightedAttributedText = highlightedAttributedText;
self.highlightedAttributedText = highlightedAttributedText;

[self notifyDidUpdateHighlightedAttributedText];
}
Expand All @@ -215,13 +221,28 @@ - (void)hideActiveLinkIfNeeded {
return;
}

_activeLinkRange = NSMakeRange(NSNotFound, 0);
_activeInTruncation = NO;
_highlightedAttributedText = nil;
[self clearActiveLink];

[self notifyDidUpdateHighlightedAttributedText];
}

- (NSAttributedString *)captureAttributedTextWithActiveInTruncation:(BOOL)activeInTruncation {
MPITextInteractableView *interactableView = self.interactableView;
if (interactableView.textRenderer) {
MPITextRenderAttributes *renderAttributes = interactableView.textRenderer.renderAttributes;
return activeInTruncation ? renderAttributes.truncationAttributedText : renderAttributes.attributedText;
} else {
return activeInTruncation ? interactableView.truncationAttributedText : interactableView.attributedText;
}
}

- (void)clearActiveLink {
self.activeLinkRange = NSMakeRange(NSNotFound, 0);
self.activeInTruncation = NO;
self.highlightedAttributedText = nil;
self.snapshotAttributedText = nil;
}

#pragma mark - Private (Menu)

- (BOOL)isMenuVisible {
Expand Down Expand Up @@ -299,15 +320,28 @@ - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
MPITextInteractableView *interactableView = self.interactableView;
CGPoint location = [gestureRecognizer locationInView:interactableView];
if (gestureRecognizer == self.interactiveGestureRecognizer) {
_activeLinkRange = [self linkRangeAtPoint:location inTruncation:&_activeInTruncation];
NSAttributedString *snapshotAttributedTextBefore = [self captureAttributedTextWithActiveInTruncation:NO];
NSAttributedString *snapshotTruncationAttributedTextBefore = [self captureAttributedTextWithActiveInTruncation:YES];
BOOL activeInTruncation = NO;
self.activeLinkRange = [self linkRangeAtPoint:location inTruncation:&activeInTruncation];
self.activeInTruncation = activeInTruncation;
NSAttributedString *snapshotAttributedTextEnd = [self captureAttributedTextWithActiveInTruncation:NO];
NSAttributedString *snapshotTruncationAttributedTextEnd = [self captureAttributedTextWithActiveInTruncation:YES];
if (snapshotAttributedTextBefore != snapshotAttributedTextEnd ||
snapshotTruncationAttributedTextBefore != snapshotTruncationAttributedTextEnd) { // The attributedText was changed
[self clearActiveLink];
}

if (self.activeLinkRange.location != NSNotFound &&
NSMaxRange(self.activeLinkRange) <= self.attributedText.length) {
if (self.activeLinkRange.location != NSNotFound) {
if (self.activeInTruncation) {
self.snapshotAttributedText = snapshotTruncationAttributedTextEnd;
} else {
self.snapshotAttributedText = snapshotAttributedTextEnd;
}
BOOL shouldInteractLink = [interactableView shouldInteractLinkWithLinkRange:self.activeLinkRange
forAttributedText:self.attributedText];
forAttributedText:self.snapshotAttributedText];
if (!shouldInteractLink) {
_activeLinkRange = NSMakeRange(NSNotFound, 0);
_activeInTruncation = NO;
[self clearActiveLink];
}
}

Expand All @@ -327,16 +361,6 @@ - (BOOL)hasActiveLink {
self.activeLinkRange.length > 0;
}

- (NSAttributedString *)attributedText {
MPITextInteractableView *interactableView = self.interactableView;
if (interactableView.textRenderer) {
MPITextRenderAttributes *renderAttributes = interactableView.textRenderer.renderAttributes;
return self.activeInTruncation ? renderAttributes.truncationAttributedText : renderAttributes.attributedText;
} else {
return self.activeInTruncation ? interactableView.truncationAttributedText : interactableView.attributedText;
}
}

- (UIPanGestureRecognizer *)grabberPanGestureRecognizer {
if (!_grabberPanGestureRecognizer) {
_grabberPanGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(grabberPanAction:)];
Expand Down
2 changes: 1 addition & 1 deletion Sources/MPITextKitBugFixer.m
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ - (BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldSetLineFragmentRect

// paragraphSpacing
CGFloat paragraphSpacing = 0;
if (paragraphStyle.paragraphSpacing > FLT_EPSILON) {
if (paragraphStyle.paragraphSpacing > FLT_EPSILON || paragraphStyle.paragraphSpacing < -FLT_EPSILON) {
NSRange charaterRange = [layoutManager characterRangeForGlyphRange:NSMakeRange(NSMaxRange(glyphRange) - 1, 1) actualGlyphRange:NULL];
NSAttributedString *attributedString = [textStorage attributedSubstringFromRange:charaterRange];
if ([attributedString.string isEqualToString:@"\n"]) {
Expand Down
Loading

0 comments on commit f50949b

Please sign in to comment.