mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-20 14:05:09 +00:00
Namespaces or un-globalifies a handful more iOS globals
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
The inverse of the square root of 2.
|
The inverse of the square root of 2.
|
||||||
Provide enough digits for the 128-bit IEEE quad (36 significant digits).
|
Provide enough digits for the 128-bit IEEE quad (36 significant digits).
|
||||||
*/
|
*/
|
||||||
extern CGFloat const M_SQRT1_2l;
|
extern CGFloat const RNSVG_M_SQRT1_2l;
|
||||||
extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
|
extern CGFloat const RNSVG_DEFAULT_FONT_SIZE;
|
||||||
|
|
||||||
@property (nonatomic, strong) NSString *name;
|
@property (nonatomic, strong) NSString *name;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
RNSVGSvgView *_svgView;
|
RNSVGSvgView *_svgView;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat const M_SQRT1_2l = 0.707106781186547524400844362104849039;
|
CGFloat const RNSVG_M_SQRT1_2l = 0.707106781186547524400844362104849039;
|
||||||
CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
|
CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
|
||||||
|
|
||||||
- (instancetype)init
|
- (instancetype)init
|
||||||
@@ -262,7 +262,7 @@ CGFloat const RNSVG_DEFAULT_FONT_SIZE = 12;
|
|||||||
CGFloat height = [self getContextHeight];
|
CGFloat height = [self getContextHeight];
|
||||||
CGFloat powX = width * width;
|
CGFloat powX = width * width;
|
||||||
CGFloat powY = height * height;
|
CGFloat powY = height * height;
|
||||||
CGFloat r = sqrt(powX + powY) * M_SQRT1_2l;
|
CGFloat r = sqrt(powX + powY) * RNSVG_M_SQRT1_2l;
|
||||||
return [RNSVGPropHelper fromRelativeWithNSString:length
|
return [RNSVGPropHelper fromRelativeWithNSString:length
|
||||||
relative:r
|
relative:r
|
||||||
offset:0
|
offset:0
|
||||||
|
|||||||
@@ -141,7 +141,8 @@
|
|||||||
scaleMultiplier:1.0];
|
scaleMultiplier:1.0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushIndices(RNSVGGlyphContext *self) {
|
- (void)pushIndices
|
||||||
|
{
|
||||||
[self->mXsIndices_ addObject:[NSNumber numberWithLong:self->mXsIndex_]];
|
[self->mXsIndices_ addObject:[NSNumber numberWithLong:self->mXsIndex_]];
|
||||||
[self->mYsIndices_ addObject:[NSNumber numberWithLong:self->mYsIndex_]];
|
[self->mYsIndices_ addObject:[NSNumber numberWithLong:self->mYsIndex_]];
|
||||||
[self->mDXsIndices_ addObject:[NSNumber numberWithLong:self->mDXsIndex_]];
|
[self->mDXsIndices_ addObject:[NSNumber numberWithLong:self->mDXsIndex_]];
|
||||||
@@ -203,7 +204,7 @@ void pushIndices(RNSVGGlyphContext *self) {
|
|||||||
[self->mRIndices_ addObject:[NSNumber numberWithLong:self->mRIndex_]];
|
[self->mRIndices_ addObject:[NSNumber numberWithLong:self->mRIndex_]];
|
||||||
|
|
||||||
[self->mFontContext_ addObject:self->topFont_];
|
[self->mFontContext_ addObject:self->topFont_];
|
||||||
pushIndices(self);
|
[self pushIndices];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +212,8 @@ void pushIndices(RNSVGGlyphContext *self) {
|
|||||||
return topFont_;
|
return topFont_;
|
||||||
}
|
}
|
||||||
|
|
||||||
RNSVGFontData *getTopOrParentFont(RNSVGGlyphContext *self, RNSVGGroup* child) {
|
- (RNSVGFontData *)getTopOrParentFont:(RNSVGGroup *)child
|
||||||
|
{
|
||||||
if (self->mTop_ > 0) {
|
if (self->mTop_ > 0) {
|
||||||
return self->topFont_;
|
return self->topFont_;
|
||||||
} else {
|
} else {
|
||||||
@@ -228,8 +230,9 @@ RNSVGFontData *getTopOrParentFont(RNSVGGlyphContext *self, RNSVGGroup* child) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushNodeAndFont(RNSVGGlyphContext *self, RNSVGGroup* node, NSDictionary* font) {
|
- (void)pushNode:(RNSVGGroup *)node andFont:(NSDictionary *)font
|
||||||
RNSVGFontData *parent = getTopOrParentFont(self, node);
|
{
|
||||||
|
RNSVGFontData *parent = [self getTopOrParentFont:node];
|
||||||
self->mTop_++;
|
self->mTop_++;
|
||||||
if (font == nil) {
|
if (font == nil) {
|
||||||
[self->mFontContext_ addObject:parent];
|
[self->mFontContext_ addObject:parent];
|
||||||
@@ -245,8 +248,8 @@ void pushNodeAndFont(RNSVGGlyphContext *self, RNSVGGroup* node, NSDictionary* fo
|
|||||||
|
|
||||||
- (void)pushContext:(RNSVGGroup*)node
|
- (void)pushContext:(RNSVGGroup*)node
|
||||||
font:(NSDictionary*)font {
|
font:(NSDictionary*)font {
|
||||||
pushNodeAndFont(self, node, font);
|
[self pushNode:node andFont:font];
|
||||||
pushIndices(self);
|
[self pushIndices];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pushContext:(RNSVGText*)node
|
- (void)pushContext:(RNSVGText*)node
|
||||||
@@ -256,7 +259,7 @@ void pushNodeAndFont(RNSVGGlyphContext *self, RNSVGGroup* node, NSDictionary* fo
|
|||||||
deltaX:(NSArray*)deltaX
|
deltaX:(NSArray*)deltaX
|
||||||
deltaY:(NSArray*)deltaY
|
deltaY:(NSArray*)deltaY
|
||||||
rotate:(NSArray*)rotate {
|
rotate:(NSArray*)rotate {
|
||||||
pushNodeAndFont(self, (RNSVGGroup*)node, font);
|
[self pushNode:(RNSVGGroup*)node andFont:font];
|
||||||
if (x != nil && [x count] != 0) {
|
if (x != nil && [x count] != 0) {
|
||||||
mXsIndex_++;
|
mXsIndex_++;
|
||||||
mXIndex_ = -1;
|
mXIndex_ = -1;
|
||||||
@@ -292,7 +295,7 @@ void pushNodeAndFont(RNSVGGlyphContext *self, RNSVGGroup* node, NSDictionary* fo
|
|||||||
mRs_ = [rotate valueForKeyPath:@"self.doubleValue"];
|
mRs_ = [rotate valueForKeyPath:@"self.doubleValue"];
|
||||||
[mRsContext_ addObject:mRs_];
|
[mRsContext_ addObject:mRs_];
|
||||||
}
|
}
|
||||||
pushIndices(self);
|
[self pushIndices];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)popContext {
|
- (void)popContext {
|
||||||
@@ -346,7 +349,8 @@ void pushNodeAndFont(RNSVGGlyphContext *self, RNSVGGroup* node, NSDictionary* fo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void incrementIndices(NSMutableArray *indices, long topIndex) {
|
+ (void)incrementIndices:(NSMutableArray *)indices topIndex:(long)topIndex
|
||||||
|
{
|
||||||
for (long index = topIndex; index >= 0; index--) {
|
for (long index = topIndex; index >= 0; index--) {
|
||||||
long xIndex = [[indices objectAtIndex:index] longValue];
|
long xIndex = [[indices objectAtIndex:index] longValue];
|
||||||
[indices setObject:[NSNumber numberWithLong:xIndex + 1] atIndexedSubscript:index];
|
[indices setObject:[NSNumber numberWithLong:xIndex + 1] atIndexedSubscript:index];
|
||||||
@@ -389,7 +393,7 @@ void incrementIndices(NSMutableArray *indices, long topIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (double)nextXWithDouble:(double)advance {
|
- (double)nextXWithDouble:(double)advance {
|
||||||
incrementIndices(mXIndices_, mXsIndex_);
|
[RNSVGGlyphContext incrementIndices:mXIndices_ topIndex:mXsIndex_];
|
||||||
long nextIndex = mXIndex_ + 1;
|
long nextIndex = mXIndex_ + 1;
|
||||||
if (nextIndex < [mXs_ count]) {
|
if (nextIndex < [mXs_ count]) {
|
||||||
mDX_ = 0;
|
mDX_ = 0;
|
||||||
@@ -406,7 +410,7 @@ void incrementIndices(NSMutableArray *indices, long topIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (double)nextY {
|
- (double)nextY {
|
||||||
incrementIndices(mYIndices_, mYsIndex_);
|
[RNSVGGlyphContext incrementIndices:mYIndices_ topIndex:mYsIndex_];
|
||||||
long nextIndex = mYIndex_ + 1;
|
long nextIndex = mYIndex_ + 1;
|
||||||
if (nextIndex < [mYs_ count]) {
|
if (nextIndex < [mYs_ count]) {
|
||||||
mDY_ = 0;
|
mDY_ = 0;
|
||||||
@@ -422,7 +426,7 @@ void incrementIndices(NSMutableArray *indices, long topIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (double)nextDeltaX {
|
- (double)nextDeltaX {
|
||||||
incrementIndices(mDXIndices_, mDXsIndex_);
|
[RNSVGGlyphContext incrementIndices:mDXIndices_ topIndex:mDXsIndex_];
|
||||||
long nextIndex = mDXIndex_ + 1;
|
long nextIndex = mDXIndex_ + 1;
|
||||||
if (nextIndex < [mDXs_ count]) {
|
if (nextIndex < [mDXs_ count]) {
|
||||||
mDXIndex_ = nextIndex;
|
mDXIndex_ = nextIndex;
|
||||||
@@ -438,7 +442,7 @@ void incrementIndices(NSMutableArray *indices, long topIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (double)nextDeltaY {
|
- (double)nextDeltaY {
|
||||||
incrementIndices(mDYIndices_, mDYsIndex_);
|
[RNSVGGlyphContext incrementIndices:mDYIndices_ topIndex:mDYsIndex_];
|
||||||
long nextIndex = mDYIndex_ + 1;
|
long nextIndex = mDYIndex_ + 1;
|
||||||
if (nextIndex < [mDYs_ count]) {
|
if (nextIndex < [mDYs_ count]) {
|
||||||
mDYIndex_ = nextIndex;
|
mDYIndex_ = nextIndex;
|
||||||
@@ -454,7 +458,7 @@ void incrementIndices(NSMutableArray *indices, long topIndex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSNumber*)nextRotation {
|
- (NSNumber*)nextRotation {
|
||||||
incrementIndices(mRIndices_, mRsIndex_);
|
[RNSVGGlyphContext incrementIndices:mRIndices_ topIndex:mRsIndex_];
|
||||||
long nextIndex = mRIndex_ + 1;
|
long nextIndex = mRIndex_ + 1;
|
||||||
long count = [mRs_ count];
|
long count = [mRs_ count];
|
||||||
if (nextIndex < count) {
|
if (nextIndex < count) {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#import "RNSVGTextProperties.h"
|
#import "RNSVGTextProperties.h"
|
||||||
#import "RNSVGFontData.h"
|
#import "RNSVGFontData.h"
|
||||||
|
|
||||||
NSCharacterSet *separators = nil;
|
static NSCharacterSet *RNSVGTSpan_separators = nil;
|
||||||
static double radToDeg = 180 / M_PI;
|
static double RNSVGTSpan_radToDeg = 180 / M_PI;
|
||||||
|
|
||||||
@implementation RNSVGTSpan
|
@implementation RNSVGTSpan
|
||||||
{
|
{
|
||||||
@@ -30,8 +30,8 @@ static double radToDeg = 180 / M_PI;
|
|||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
|
|
||||||
if (separators == nil) {
|
if (RNSVGTSpan_separators == nil) {
|
||||||
separators = [NSCharacterSet whitespaceCharacterSet];
|
RNSVGTSpan_separators = [NSCharacterSet whitespaceCharacterSet];
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -272,7 +272,7 @@ static double radToDeg = 180 / M_PI;
|
|||||||
enum RNSVGTextAnchor textAnchor = font->textAnchor;
|
enum RNSVGTextAnchor textAnchor = font->textAnchor;
|
||||||
CGRect textBounds = CTLineGetBoundsWithOptions(line, 0);
|
CGRect textBounds = CTLineGetBoundsWithOptions(line, 0);
|
||||||
double textMeasure = CGRectGetWidth(textBounds);
|
double textMeasure = CGRectGetWidth(textBounds);
|
||||||
double offset = getTextAnchorOffset(textAnchor, textMeasure);
|
double offset = [RNSVGTSpan getTextAnchorOffset:textAnchor width:textMeasure];
|
||||||
|
|
||||||
bool hasTextPath = textPath != nil;
|
bool hasTextPath = textPath != nil;
|
||||||
|
|
||||||
@@ -703,7 +703,7 @@ static double radToDeg = 180 / M_PI;
|
|||||||
|
|
||||||
CFIndex currIndex = indices[g];
|
CFIndex currIndex = indices[g];
|
||||||
char currentChar = [str characterAtIndex:currIndex];
|
char currentChar = [str characterAtIndex:currIndex];
|
||||||
bool isWordSeparator = [separators characterIsMember:currentChar];
|
bool isWordSeparator = [RNSVGTSpan_separators characterIsMember:currentChar];
|
||||||
double wordSpace = isWordSeparator ? wordSpacing : 0;
|
double wordSpace = isWordSeparator ? wordSpacing : 0;
|
||||||
double spacing = wordSpace + letterSpacing;
|
double spacing = wordSpace + letterSpacing;
|
||||||
double advance = charWidth + spacing;
|
double advance = charWidth + spacing;
|
||||||
@@ -712,7 +712,7 @@ static double radToDeg = 180 / M_PI;
|
|||||||
double y = [gc nextY];
|
double y = [gc nextY];
|
||||||
double dx = [gc nextDeltaX];
|
double dx = [gc nextDeltaX];
|
||||||
double dy = [gc nextDeltaY];
|
double dy = [gc nextDeltaY];
|
||||||
double r = [[gc nextRotation] doubleValue] / radToDeg;
|
double r = [[gc nextRotation] doubleValue] / RNSVGTSpan_radToDeg;
|
||||||
|
|
||||||
CFIndex endIndex = g + 1 == runGlyphCount ? currIndex : indices[g + 1];
|
CFIndex endIndex = g + 1 == runGlyphCount ? currIndex : indices[g + 1];
|
||||||
while (++currIndex < endIndex) {
|
while (++currIndex < endIndex) {
|
||||||
@@ -811,7 +811,7 @@ static double radToDeg = 180 / M_PI;
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGFloat getTextAnchorOffset(enum RNSVGTextAnchor textAnchor, CGFloat width)
|
+ (CGFloat)getTextAnchorOffset:(RNSVGTextAnchor)textAnchor width:(CGFloat) width
|
||||||
{
|
{
|
||||||
switch (textAnchor) {
|
switch (textAnchor) {
|
||||||
case RNSVGTextAnchorStart:
|
case RNSVGTextAnchorStart:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ static CGFloat idealFlatness = .01;
|
|||||||
/**
|
/**
|
||||||
* returns the distance between two points
|
* returns the distance between two points
|
||||||
*/
|
*/
|
||||||
CGFloat distance(CGPoint p1, CGPoint p2)
|
CGFloat RNSVGPerformanceBezier_distance(CGPoint p1, CGPoint p2)
|
||||||
{
|
{
|
||||||
CGFloat dx = p2.x - p1.x;
|
CGFloat dx = p2.x - p1.x;
|
||||||
CGFloat dy = p2.y - p1.y;
|
CGFloat dy = p2.y - p1.y;
|
||||||
@@ -68,7 +68,7 @@ CGFloat distance(CGPoint p1, CGPoint p2)
|
|||||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void subdivideBezierAtT(const CGPoint bez[4], CGPoint bez1[4], CGPoint bez2[4], CGFloat t)
|
void RNSVGPerformanceBezier_subdivideBezierAtT(const CGPoint bez[4], CGPoint bez1[4], CGPoint bez2[4], CGFloat t)
|
||||||
{
|
{
|
||||||
CGPoint q;
|
CGPoint q;
|
||||||
CGFloat mt = 1 - t;
|
CGFloat mt = 1 - t;
|
||||||
@@ -94,10 +94,10 @@ void subdivideBezierAtT(const CGPoint bez[4], CGPoint bez1[4], CGPoint bez2[4],
|
|||||||
bez1[3].y = bez2[0].y = mt * bez1[2].y + t * bez2[1].y;
|
bez1[3].y = bez2[0].y = mt * bez1[2].y + t * bez2[1].y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat *length, NSMutableArray *lengths) {
|
void RNSVGPerformanceBezier_addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat *length, NSMutableArray *lengths) {
|
||||||
NSArray *line = @[[NSValue valueWithCGPoint:*last], [NSValue valueWithCGPoint:*next]];
|
NSArray *line = @[[NSValue valueWithCGPoint:*last], [NSValue valueWithCGPoint:*next]];
|
||||||
[lines addObject:line];
|
[lines addObject:line];
|
||||||
*length += distance(*last, *next);
|
*length += RNSVGPerformanceBezier_distance(*last, *next);
|
||||||
[lengths addObject:[NSNumber numberWithDouble:*length]];
|
[lengths addObject:[NSNumber numberWithDouble:*length]];
|
||||||
*last = *next;
|
*last = *next;
|
||||||
}
|
}
|
||||||
@@ -138,7 +138,7 @@ void addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat
|
|||||||
|
|
||||||
case kCGPathElementAddLineToPoint: {
|
case kCGPathElementAddLineToPoint: {
|
||||||
CGPoint next = element.point;
|
CGPoint next = element.point;
|
||||||
addLine(&last, &next, lines, &length, lengths);
|
RNSVGPerformanceBezier_addLine(&last, &next, lines, &length, lengths);
|
||||||
lineCount++;
|
lineCount++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -166,20 +166,20 @@ void addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat
|
|||||||
CGPoint ctrl2 = bez[2];
|
CGPoint ctrl2 = bez[2];
|
||||||
CGPoint next = bez[3];
|
CGPoint next = bez[3];
|
||||||
CGFloat polyLen =
|
CGFloat polyLen =
|
||||||
distance(last, ctrl1) +
|
RNSVGPerformanceBezier_distance(last, ctrl1) +
|
||||||
distance(ctrl1, ctrl2) +
|
RNSVGPerformanceBezier_distance(ctrl1, ctrl2) +
|
||||||
distance(ctrl2, next);
|
RNSVGPerformanceBezier_distance(ctrl2, next);
|
||||||
CGFloat chordLen = distance(last, next);
|
CGFloat chordLen = RNSVGPerformanceBezier_distance(last, next);
|
||||||
CGFloat error = polyLen - chordLen;
|
CGFloat error = polyLen - chordLen;
|
||||||
|
|
||||||
// if the error is less than our accepted level of error
|
// if the error is less than our accepted level of error
|
||||||
// then add a line, else, split the curve in half
|
// then add a line, else, split the curve in half
|
||||||
if (error <= idealFlatness) {
|
if (error <= idealFlatness) {
|
||||||
addLine(&last, &next, lines, &length, lengths);
|
RNSVGPerformanceBezier_addLine(&last, &next, lines, &length, lengths);
|
||||||
lineCount++;
|
lineCount++;
|
||||||
} else {
|
} else {
|
||||||
CGPoint bez1[4], bez2[4];
|
CGPoint bez1[4], bez2[4];
|
||||||
subdivideBezierAtT(bez, bez1, bez2, .5);
|
RNSVGPerformanceBezier_subdivideBezierAtT(bez, bez1, bez2, .5);
|
||||||
[curves addObject:[NSValue valueWithBytes:&bez2 objCType:@encode(CGPoint[4])]];
|
[curves addObject:[NSValue valueWithBytes:&bez2 objCType:@encode(CGPoint[4])]];
|
||||||
[curves addObject:[NSValue valueWithBytes:&bez1 objCType:@encode(CGPoint[4])]];
|
[curves addObject:[NSValue valueWithBytes:&bez1 objCType:@encode(CGPoint[4])]];
|
||||||
curveIndex += 2;
|
curveIndex += 2;
|
||||||
@@ -190,7 +190,7 @@ void addLine(CGPoint *last, const CGPoint *next, NSMutableArray *lines, CGFloat
|
|||||||
|
|
||||||
case kCGPathElementCloseSubpath: {
|
case kCGPathElementCloseSubpath: {
|
||||||
CGPoint next = origin;
|
CGPoint next = origin;
|
||||||
addLine(&last, &next, lines, &length, lengths);
|
RNSVGPerformanceBezier_addLine(&last, &next, lines, &length, lengths);
|
||||||
lineCount++;
|
lineCount++;
|
||||||
isClosed = YES;
|
isClosed = YES;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert one element to RNSVGBezierElement and save to array
|
// Convert one element to RNSVGBezierElement and save to array
|
||||||
void GetBezierElements(void *info, const CGPathElement *element)
|
void RNSVGBezierElement_getBezierElements(void *info, const CGPathElement *element)
|
||||||
{
|
{
|
||||||
NSMutableArray *bezierElements = (__bridge NSMutableArray *)info;
|
NSMutableArray *bezierElements = (__bridge NSMutableArray *)info;
|
||||||
if (element)
|
if (element)
|
||||||
@@ -69,7 +69,7 @@ void GetBezierElements(void *info, const CGPathElement *element)
|
|||||||
+ (NSArray *) elementsFromCGPath:(CGPathRef)path
|
+ (NSArray *) elementsFromCGPath:(CGPathRef)path
|
||||||
{
|
{
|
||||||
NSMutableArray *elements = [NSMutableArray array];
|
NSMutableArray *elements = [NSMutableArray array];
|
||||||
CGPathApply(path, (__bridge void *)elements, GetBezierElements);
|
CGPathApply(path, (__bridge void *)elements, RNSVGBezierElement_getBezierElements);
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user