mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Svg WIP
This commit is contained in:
parent
e27c17b2ba
commit
a5a78ab2b0
@ -194,6 +194,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
var keyboardViewManager: KeyboardViewManager?
|
||||
|
||||
var updateSupportedOrientations: (() -> Void)?
|
||||
|
||||
public func updateMasterDetailsBlackout(_ blackout: MasterDetailLayoutBlackout?, transition: ContainedViewLayoutTransition) {
|
||||
self.masterDetailsBlackout = blackout
|
||||
if isViewLoaded {
|
||||
@ -928,6 +930,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
if notifyGlobalOverlayControllersUpdated {
|
||||
self.globalOverlayControllersUpdated?()
|
||||
}
|
||||
|
||||
self.updateSupportedOrientations?()
|
||||
}
|
||||
|
||||
private func controllerRemoved(_ controller: ViewController) {
|
||||
|
@ -725,6 +725,36 @@ public class Window1 {
|
||||
if let rootController = self._rootController {
|
||||
if let rootController = rootController as? NavigationController {
|
||||
rootController.statusBarHost = self.statusBarHost
|
||||
rootController.updateSupportedOrientations = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .all)
|
||||
let orientationToLock: UIInterfaceOrientationMask
|
||||
if strongSelf.windowLayout.size.width < strongSelf.windowLayout.size.height {
|
||||
orientationToLock = .portrait
|
||||
} else {
|
||||
orientationToLock = .landscape
|
||||
}
|
||||
if let _rootController = strongSelf._rootController {
|
||||
supportedOrientations = supportedOrientations.intersection(_rootController.combinedSupportedOrientations(currentOrientationToLock: orientationToLock))
|
||||
}
|
||||
supportedOrientations = supportedOrientations.intersection(strongSelf.presentationContext.combinedSupportedOrientations(currentOrientationToLock: orientationToLock))
|
||||
supportedOrientations = supportedOrientations.intersection(strongSelf.overlayPresentationContext.combinedSupportedOrientations(currentOrientationToLock: orientationToLock))
|
||||
|
||||
var resolvedOrientations: UIInterfaceOrientationMask
|
||||
switch strongSelf.windowLayout.metrics.widthClass {
|
||||
case .regular:
|
||||
resolvedOrientations = supportedOrientations.regularSize
|
||||
case .compact:
|
||||
resolvedOrientations = supportedOrientations.compactSize
|
||||
}
|
||||
if resolvedOrientations.isEmpty {
|
||||
resolvedOrientations = [.portrait]
|
||||
}
|
||||
strongSelf.hostView.updateSupportedInterfaceOrientations(resolvedOrientations)
|
||||
}
|
||||
rootController.keyboardViewManager = self.keyboardViewManager
|
||||
rootController.inCallNavigate = { [weak self] in
|
||||
self?.inCallNavigate?()
|
||||
|
@ -514,7 +514,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
let removeAction: (RemoveStickerPackOption) -> Void = { action in
|
||||
let _ = (removeStickerPackInteractively(postbox: context.account.postbox, id: archivedItem.info.id, option: .archive)
|
||||
let _ = (removeStickerPackInteractively(postbox: context.account.postbox, id: archivedItem.info.id, option: action)
|
||||
|> deliverOnMainQueue).start(next: { indexAndItems in
|
||||
guard let (positionInList, items) = indexAndItems else {
|
||||
return
|
||||
@ -530,7 +530,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
||||
}
|
||||
}
|
||||
|
||||
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: presentationData.strings.StickerPackActionInfo_ArchivedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(archivedItem.info.title).0, undo: true, info: archivedItem.info, topItem: archivedItem.topItems.first, account: context.account), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
|
||||
navigationControllerImpl?()?.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .stickersModified(title: action == .archive ? presentationData.strings.StickerPackActionInfo_ArchivedTitle : presentationData.strings.StickerPackActionInfo_RemovedTitle, text: presentationData.strings.StickerPackActionInfo_RemovedText(archivedItem.info.title).0, undo: true, info: archivedItem.info, topItem: archivedItem.topItems.first, account: context.account), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { action in
|
||||
if case .undo = action {
|
||||
let _ = addStickerPackInteractively(postbox: context.account.postbox, info: archivedItem.info, items: items, positionInList: positionInList).start()
|
||||
}
|
||||
|
@ -640,11 +640,12 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
|
||||
private func preparePatternEditing() {
|
||||
if let entry = self.entry, case let .wallpaper(wallpaper, _) = entry, case let .file(file) = wallpaper {
|
||||
if let size = file.file.dimensions?.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0)) {
|
||||
let dimensions = file.file.dimensions ?? PixelDimensions(width: 1440, height: 2960)
|
||||
|
||||
let size = dimensions.cgSize.fitted(CGSize(width: 1280.0, height: 1280.0))
|
||||
let _ = self.context.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedPatternWallpaperMaskRepresentation(size: size), complete: false, fetch: true).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
|
||||
if enabled {
|
||||
|
@ -24,4 +24,7 @@ static_library(
|
||||
exported_linker_flags = [
|
||||
"-lxml2",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/GZip:GZip",
|
||||
],
|
||||
)
|
||||
|
@ -10,19 +10,119 @@ CGSize aspectFillSize(CGSize size, CGSize bounds) {
|
||||
return CGSizeMake(floor(size.width * scale), floor(size.height * scale));
|
||||
}
|
||||
|
||||
@interface SvgXMLParsingDelegate : NSObject <NSXMLParserDelegate> {
|
||||
NSString *_elementName;
|
||||
NSString *_currentStyleString;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong, readonly) NSMutableDictionary<NSString *, NSString *> *styles;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SvgXMLParsingDelegate
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_styles = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict {
|
||||
_elementName = elementName;
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||
if ([_elementName isEqualToString:@"style"]) {
|
||||
int currentClassNameStartIndex = -1;
|
||||
int currentClassContentsStartIndex = -1;
|
||||
|
||||
NSString *currentClassName = nil;
|
||||
|
||||
NSCharacterSet *alphanumeric = [NSCharacterSet alphanumericCharacterSet];
|
||||
|
||||
for (int i = 0; i < _currentStyleString.length; i++) {
|
||||
unichar c = [_currentStyleString characterAtIndex:i];
|
||||
if (currentClassNameStartIndex != -1) {
|
||||
if (![alphanumeric characterIsMember:c]) {
|
||||
currentClassName = [_currentStyleString substringWithRange:NSMakeRange(currentClassNameStartIndex, i - currentClassNameStartIndex)];
|
||||
currentClassNameStartIndex = -1;
|
||||
}
|
||||
} else if (currentClassContentsStartIndex != -1) {
|
||||
if (c == '}') {
|
||||
NSString *classContents = [_currentStyleString substringWithRange:NSMakeRange(currentClassContentsStartIndex, i - currentClassContentsStartIndex)];
|
||||
if (currentClassName != nil && classContents != nil) {
|
||||
_styles[currentClassName] = classContents;
|
||||
currentClassName = nil;
|
||||
}
|
||||
currentClassContentsStartIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentClassNameStartIndex == -1 && currentClassContentsStartIndex == -1) {
|
||||
if (c == '.') {
|
||||
currentClassNameStartIndex = i + 1;
|
||||
} else if (c == '{') {
|
||||
currentClassContentsStartIndex = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_elementName = nil;
|
||||
}
|
||||
|
||||
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
|
||||
if ([_elementName isEqualToString:@"style"]) {
|
||||
if (_currentStyleString == nil) {
|
||||
_currentStyleString = string;
|
||||
} else {
|
||||
_currentStyleString = [_currentStyleString stringByAppendingString:string];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
char *zeroTerminatedData = malloc(data.length + 1);
|
||||
[data getBytes:zeroTerminatedData length:data.length];
|
||||
zeroTerminatedData[data.length] = 0;
|
||||
NSDate *startTime = [NSDate date];
|
||||
|
||||
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
|
||||
if (parser == nil) {
|
||||
return nil;
|
||||
}
|
||||
SvgXMLParsingDelegate *delegate = [[SvgXMLParsingDelegate alloc] init];
|
||||
parser.delegate = delegate;
|
||||
[parser parse];
|
||||
|
||||
NSMutableString *xmlString = [[NSMutableString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
if (xmlString == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
for (NSString *styleName in delegate.styles) {
|
||||
NSString *styleValue = delegate.styles[styleName];
|
||||
[xmlString replaceOccurrencesOfString:[NSString stringWithFormat:@"class=\"%@\"", styleName] withString:[NSString stringWithFormat:@"style=\"%@\"", styleValue] options:0 range:NSMakeRange(0, xmlString.length)];
|
||||
}
|
||||
|
||||
char *zeroTerminatedData = xmlString.UTF8String;
|
||||
|
||||
NSVGimage *image = nsvgParse(zeroTerminatedData, "px", 96);
|
||||
if (image == nil || image->width < 1.0f || image->height < 1.0f) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
double deltaTime = -1.0f * [startTime timeIntervalSinceNow];
|
||||
printf("parseTime = %f\n", deltaTime);
|
||||
|
||||
startTime = [NSDate date];
|
||||
|
||||
UIColor *backgroundColor = [UIColor blackColor];
|
||||
UIColor *foregroundColor = [UIColor whiteColor];
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, true, 1.0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
CGContextScaleCTM(context, size.width / image->width, size.height / image->height);
|
||||
|
||||
@ -32,7 +132,7 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
}
|
||||
|
||||
if (shape->fill.type != NSVG_PAINT_NONE) {
|
||||
CGContextSetFillColorWithColor(context, [[UIColor blackColor] colorWithAlphaComponent:shape->opacity].CGColor);
|
||||
CGContextSetFillColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor);
|
||||
|
||||
for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
|
||||
CGContextBeginPath(context);
|
||||
@ -40,7 +140,6 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
for (int i = 0; i < path->npts - 1; i += 3) {
|
||||
float *p = &path->pts[i * 2];
|
||||
CGContextAddCurveToPoint(context, p[2], p[3], p[4], p[5], p[6], p[7]);
|
||||
//drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
||||
}
|
||||
|
||||
switch (shape->fillRule) {
|
||||
@ -55,8 +154,8 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
}
|
||||
|
||||
if (shape->stroke.type != NSVG_PAINT_NONE) {
|
||||
CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] colorWithAlphaComponent:shape->opacity].CGColor);
|
||||
//CGContextSetMiterLimit(context, shape->miterLimit);
|
||||
CGContextSetStrokeColorWithColor(context, [foregroundColor colorWithAlphaComponent:shape->opacity].CGColor);
|
||||
CGContextSetMiterLimit(context, shape->miterLimit);
|
||||
|
||||
CGContextSetLineWidth(context, shape->strokeWidth);
|
||||
switch (shape->strokeLineCap) {
|
||||
@ -92,7 +191,6 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
for (int i = 0; i < path->npts - 1; i += 3) {
|
||||
float *p = &path->pts[i * 2];
|
||||
CGContextAddCurveToPoint(context, p[2], p[3], p[4], p[5], p[6], p[7]);
|
||||
//drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]);
|
||||
}
|
||||
|
||||
if (path->closed) {
|
||||
@ -106,6 +204,9 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size) {
|
||||
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
deltaTime = -1.0f * [startTime timeIntervalSinceNow];
|
||||
printf("drawingTime = %f\n", deltaTime);
|
||||
|
||||
nsvgDelete(image);
|
||||
|
||||
return resultImage;
|
||||
|
@ -29,9 +29,11 @@
|
||||
#ifndef NANOSVG_H
|
||||
#define NANOSVG_H
|
||||
|
||||
#ifndef NANOSVG_CPLUSPLUS
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes.
|
||||
//
|
||||
@ -45,15 +47,15 @@ extern "C" {
|
||||
// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose
|
||||
// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters.
|
||||
//
|
||||
// The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
|
||||
// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'.
|
||||
// DPI (dots-per-inch) controls how the unit conversion is done.
|
||||
//
|
||||
// If you don't know or care about the units stuff, "px" and 96 should get you going.
|
||||
|
||||
|
||||
/* Example Usage:
|
||||
// Load
|
||||
NSVGImage* image;
|
||||
// Load SVG
|
||||
NSVGimage* image;
|
||||
image = nsvgParseFromFile("test.svg", "px", 96);
|
||||
printf("size: %f x %f\n", image->width, image->height);
|
||||
// Use...
|
||||
@ -73,30 +75,30 @@ enum NSVGpaintType {
|
||||
NSVG_PAINT_NONE = 0,
|
||||
NSVG_PAINT_COLOR = 1,
|
||||
NSVG_PAINT_LINEAR_GRADIENT = 2,
|
||||
NSVG_PAINT_RADIAL_GRADIENT = 3,
|
||||
NSVG_PAINT_RADIAL_GRADIENT = 3
|
||||
};
|
||||
|
||||
enum NSVGspreadType {
|
||||
NSVG_SPREAD_PAD = 0,
|
||||
NSVG_SPREAD_REFLECT = 1,
|
||||
NSVG_SPREAD_REPEAT = 2,
|
||||
NSVG_SPREAD_REPEAT = 2
|
||||
};
|
||||
|
||||
enum NSVGlineJoin {
|
||||
NSVG_JOIN_MITER = 0,
|
||||
NSVG_JOIN_ROUND = 1,
|
||||
NSVG_JOIN_BEVEL = 2,
|
||||
NSVG_JOIN_BEVEL = 2
|
||||
};
|
||||
|
||||
enum NSVGlineCap {
|
||||
NSVG_CAP_BUTT = 0,
|
||||
NSVG_CAP_ROUND = 1,
|
||||
NSVG_CAP_SQUARE = 2,
|
||||
NSVG_CAP_SQUARE = 2
|
||||
};
|
||||
|
||||
enum NSVGfillRule {
|
||||
NSVG_FILLRULE_NONZERO = 0,
|
||||
NSVG_FILLRULE_EVENODD = 1,
|
||||
NSVG_FILLRULE_EVENODD = 1
|
||||
};
|
||||
|
||||
enum NSVGflags {
|
||||
@ -145,10 +147,10 @@ typedef struct NSVGshape
|
||||
char strokeDashCount; // Number of dash values in dash array.
|
||||
char strokeLineJoin; // Stroke join type.
|
||||
char strokeLineCap; // Stroke cap type.
|
||||
float miterLimit; // Miter limit
|
||||
char fillRule; // Fill rule, see NSVGfillRule.
|
||||
unsigned char flags; // Logical or of NSVG_FLAGS_* flags
|
||||
float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
|
||||
|
||||
NSVGpath* paths; // Linked list of paths in the image.
|
||||
struct NSVGshape* next; // Pointer to next shape, or NULL if last element.
|
||||
} NSVGshape;
|
||||
@ -157,7 +159,6 @@ typedef struct NSVGimage
|
||||
{
|
||||
float width; // Width of the image.
|
||||
float height; // Height of the image.
|
||||
float realBounds[4];
|
||||
NSVGshape* shapes; // Linked list of shapes in the image.
|
||||
} NSVGimage;
|
||||
|
||||
@ -168,11 +169,16 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi)
|
||||
// Important note: changes the string.
|
||||
NSVGimage* nsvgParse(char* input, const char* units, float dpi);
|
||||
|
||||
// Deletes list of paths.
|
||||
// Duplicates a path.
|
||||
NSVGpath* nsvgDuplicatePath(NSVGpath* p);
|
||||
|
||||
// Deletes an image.
|
||||
void nsvgDelete(NSVGimage* image);
|
||||
|
||||
#ifndef NANOSVG_CPLUSPLUS
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // NANOSVG_H
|
||||
@ -184,7 +190,7 @@ void nsvgDelete(NSVGimage* image);
|
||||
#include <math.h>
|
||||
|
||||
#define NSVG_PI (3.14159265358979323846264338327f)
|
||||
#define NSVG_KAPPA90 (0.5522847493f) // Lenght proportional to radius of a cubic bezier handle for 90deg arcs.
|
||||
#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs.
|
||||
|
||||
#define NSVG_ALIGN_MIN 0
|
||||
#define NSVG_ALIGN_MID 1
|
||||
@ -216,7 +222,7 @@ static int nsvg__isspace(char c)
|
||||
|
||||
static int nsvg__isdigit(char c)
|
||||
{
|
||||
return strchr("0123456789", c) != 0;
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
static int nsvg__isnum(char c)
|
||||
@ -280,6 +286,9 @@ static void nsvg__parseElement(char* s,
|
||||
|
||||
// Get attribs
|
||||
while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
|
||||
char* name = NULL;
|
||||
char* value = NULL;
|
||||
|
||||
// Skip white space before the attrib name
|
||||
while (*s && nsvg__isspace(*s)) s++;
|
||||
if (!*s) break;
|
||||
@ -287,7 +296,7 @@ static void nsvg__parseElement(char* s,
|
||||
end = 1;
|
||||
break;
|
||||
}
|
||||
attr[nattr++] = s;
|
||||
name = s;
|
||||
// Find end of the attrib name.
|
||||
while (*s && !nsvg__isspace(*s) && *s != '=') s++;
|
||||
if (*s) { *s++ = '\0'; }
|
||||
@ -297,9 +306,15 @@ static void nsvg__parseElement(char* s,
|
||||
quote = *s;
|
||||
s++;
|
||||
// Store value and find the end of it.
|
||||
attr[nattr++] = s;
|
||||
value = s;
|
||||
while (*s && *s != quote) s++;
|
||||
if (*s) { *s++ = '\0'; }
|
||||
|
||||
// Store only well formed attributes
|
||||
if (name && value) {
|
||||
attr[nattr++] = name;
|
||||
attr[nattr++] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// List terminator
|
||||
@ -350,7 +365,7 @@ int nsvg__parseXML(char* input,
|
||||
|
||||
enum NSVGgradientUnits {
|
||||
NSVG_USER_SPACE = 0,
|
||||
NSVG_OBJECT_SPACE = 1,
|
||||
NSVG_OBJECT_SPACE = 1
|
||||
};
|
||||
|
||||
#define NSVG_MAX_DASHES 8
|
||||
@ -365,7 +380,7 @@ enum NSVGunits {
|
||||
NSVG_UNITS_IN,
|
||||
NSVG_UNITS_PERCENT,
|
||||
NSVG_UNITS_EM,
|
||||
NSVG_UNITS_EX,
|
||||
NSVG_UNITS_EX
|
||||
};
|
||||
|
||||
typedef struct NSVGcoordinate {
|
||||
@ -415,6 +430,7 @@ typedef struct NSVGattrib
|
||||
int strokeDashCount;
|
||||
char strokeLineJoin;
|
||||
char strokeLineCap;
|
||||
float miterLimit;
|
||||
char fillRule;
|
||||
float fontSize;
|
||||
unsigned int stopColor;
|
||||
@ -425,13 +441,6 @@ typedef struct NSVGattrib
|
||||
char visible;
|
||||
} NSVGattrib;
|
||||
|
||||
typedef struct NSVGstyles
|
||||
{
|
||||
char* name;
|
||||
char* description;
|
||||
struct NSVGstyles* next;
|
||||
} NSVGstyles;
|
||||
|
||||
typedef struct NSVGparser
|
||||
{
|
||||
NSVGattrib attr[NSVG_MAX_ATTR];
|
||||
@ -441,14 +450,13 @@ typedef struct NSVGparser
|
||||
int cpts;
|
||||
NSVGpath* plist;
|
||||
NSVGimage* image;
|
||||
NSVGstyles* styles;
|
||||
NSVGgradientData* gradients;
|
||||
NSVGshape* shapesTail;
|
||||
float viewMinx, viewMiny, viewWidth, viewHeight;
|
||||
int alignX, alignY, alignType;
|
||||
float dpi;
|
||||
char pathFlag;
|
||||
char defsFlag;
|
||||
char styleFlag;
|
||||
} NSVGparser;
|
||||
|
||||
static void nsvg__xformIdentity(float* t)
|
||||
@ -631,6 +639,7 @@ static NSVGparser* nsvg__createParser()
|
||||
p->attr[0].strokeWidth = 1;
|
||||
p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
|
||||
p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
|
||||
p->attr[0].miterLimit = 4;
|
||||
p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
|
||||
p->attr[0].hasFill = 1;
|
||||
p->attr[0].visible = 1;
|
||||
@ -644,17 +653,6 @@ error:
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static void nsvg__deleteStyles(NSVGstyles* style) {
|
||||
while (style) {
|
||||
NSVGstyles *next = style->next;
|
||||
if (style->name!= NULL)
|
||||
free(style->name);
|
||||
if (style->description != NULL)
|
||||
free(style->description);
|
||||
free(style);
|
||||
style = next;
|
||||
}
|
||||
}
|
||||
|
||||
static void nsvg__deletePaths(NSVGpath* path)
|
||||
{
|
||||
@ -687,7 +685,6 @@ static void nsvg__deleteGradientData(NSVGgradientData* grad)
|
||||
static void nsvg__deleteParser(NSVGparser* p)
|
||||
{
|
||||
if (p != NULL) {
|
||||
nsvg__deleteStyles(p->styles);
|
||||
nsvg__deletePaths(p->plist);
|
||||
nsvg__deleteGradientData(p->gradients);
|
||||
nsvgDelete(p->image);
|
||||
@ -941,7 +938,7 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
{
|
||||
NSVGattrib* attr = nsvg__getAttr(p);
|
||||
float scale = 1.0f;
|
||||
NSVGshape *shape, *cur, *prev;
|
||||
NSVGshape* shape;
|
||||
NSVGpath* path;
|
||||
int i;
|
||||
|
||||
@ -956,11 +953,12 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
scale = nsvg__getAverageScale(attr->xform);
|
||||
shape->strokeWidth = attr->strokeWidth * scale;
|
||||
shape->strokeDashOffset = attr->strokeDashOffset * scale;
|
||||
shape->strokeDashCount = attr->strokeDashCount;
|
||||
shape->strokeDashCount = (char)attr->strokeDashCount;
|
||||
for (i = 0; i < attr->strokeDashCount; i++)
|
||||
shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
|
||||
shape->strokeLineJoin = attr->strokeLineJoin;
|
||||
shape->strokeLineCap = attr->strokeLineCap;
|
||||
shape->miterLimit = attr->miterLimit;
|
||||
shape->fillRule = attr->fillRule;
|
||||
shape->opacity = attr->opacity;
|
||||
|
||||
@ -1016,16 +1014,11 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
|
||||
|
||||
// Add to tail
|
||||
prev = NULL;
|
||||
cur = p->image->shapes;
|
||||
while (cur != NULL) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
if (prev == NULL)
|
||||
if (p->image->shapes == NULL)
|
||||
p->image->shapes = shape;
|
||||
else
|
||||
prev->next = shape;
|
||||
p->shapesTail->next = shape;
|
||||
p->shapesTail = shape;
|
||||
|
||||
return;
|
||||
|
||||
@ -1089,6 +1082,66 @@ error:
|
||||
}
|
||||
}
|
||||
|
||||
// We roll our own string to float because the std library one uses locale and messes things up.
|
||||
static double nsvg__atof(const char* s)
|
||||
{
|
||||
char* cur = (char*)s;
|
||||
char* end = NULL;
|
||||
double res = 0.0, sign = 1.0;
|
||||
long long intPart = 0, fracPart = 0;
|
||||
char hasIntPart = 0, hasFracPart = 0;
|
||||
|
||||
// Parse optional sign
|
||||
if (*cur == '+') {
|
||||
cur++;
|
||||
} else if (*cur == '-') {
|
||||
sign = -1;
|
||||
cur++;
|
||||
}
|
||||
|
||||
// Parse integer part
|
||||
if (nsvg__isdigit(*cur)) {
|
||||
// Parse digit sequence
|
||||
intPart = strtoll(cur, &end, 10);
|
||||
if (cur != end) {
|
||||
res = (double)intPart;
|
||||
hasIntPart = 1;
|
||||
cur = end;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse fractional part.
|
||||
if (*cur == '.') {
|
||||
cur++; // Skip '.'
|
||||
if (nsvg__isdigit(*cur)) {
|
||||
// Parse digit sequence
|
||||
fracPart = strtoll(cur, &end, 10);
|
||||
if (cur != end) {
|
||||
res += (double)fracPart / pow(10.0, (double)(end - cur));
|
||||
hasFracPart = 1;
|
||||
cur = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A valid number should have integer or fractional part.
|
||||
if (!hasIntPart && !hasFracPart)
|
||||
return 0.0;
|
||||
|
||||
// Parse optional exponent
|
||||
if (*cur == 'e' || *cur == 'E') {
|
||||
long expPart = 0;
|
||||
cur++; // skip 'E'
|
||||
expPart = strtol(cur, &end, 10); // Parse digit sequence with sign
|
||||
if (cur != end) {
|
||||
res *= pow(10.0, (double)expPart);
|
||||
}
|
||||
}
|
||||
|
||||
return res * sign;
|
||||
}
|
||||
|
||||
|
||||
static const char* nsvg__parseNumber(const char* s, char* it, const int size)
|
||||
{
|
||||
const int last = size-1;
|
||||
@ -1115,7 +1168,7 @@ static const char* nsvg__parseNumber(const char* s, char* it, const int size)
|
||||
}
|
||||
}
|
||||
// exponent
|
||||
if (*s == 'e' || *s == 'E') {
|
||||
if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
|
||||
if (i < last) it[i++] = *s;
|
||||
s++;
|
||||
if (*s == '-' || *s == '+') {
|
||||
@ -1369,13 +1422,19 @@ static unsigned int nsvg__parseColor(const char* str)
|
||||
|
||||
static float nsvg__parseOpacity(const char* str)
|
||||
{
|
||||
float val = 0;
|
||||
sscanf(str, "%f", &val);
|
||||
float val = nsvg__atof(str);
|
||||
if (val < 0.0f) val = 0.0f;
|
||||
if (val > 1.0f) val = 1.0f;
|
||||
return val;
|
||||
}
|
||||
|
||||
static float nsvg__parseMiterLimit(const char* str)
|
||||
{
|
||||
float val = nsvg__atof(str);
|
||||
if (val < 0.0f) val = 0.0f;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int nsvg__parseUnits(const char* units)
|
||||
{
|
||||
if (units[0] == 'p' && units[1] == 'x')
|
||||
@ -1402,9 +1461,9 @@ static int nsvg__parseUnits(const char* units)
|
||||
static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
|
||||
{
|
||||
NSVGcoordinate coord = {0, NSVG_UNITS_USER};
|
||||
char units[32]="";
|
||||
sscanf(str, "%f%s", &coord.value, units);
|
||||
coord.units = nsvg__parseUnits(units);
|
||||
char buf[64];
|
||||
coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
|
||||
coord.value = nsvg__atof(buf);
|
||||
return coord;
|
||||
}
|
||||
|
||||
@ -1440,7 +1499,7 @@ static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int
|
||||
if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) {
|
||||
if (*na >= maxNa) return 0;
|
||||
ptr = nsvg__parseNumber(ptr, it, 64);
|
||||
args[(*na)++] = (float)atof(it);
|
||||
args[(*na)++] = (float)nsvg__atof(it);
|
||||
} else {
|
||||
++ptr;
|
||||
}
|
||||
@ -1596,7 +1655,7 @@ static char nsvg__parseLineJoin(const char* str)
|
||||
else if (strcmp(str, "bevel") == 0)
|
||||
return NSVG_JOIN_BEVEL;
|
||||
// TODO: handle inherit.
|
||||
return NSVG_CAP_BUTT;
|
||||
return NSVG_JOIN_MITER;
|
||||
}
|
||||
|
||||
static char nsvg__parseFillRule(const char* str)
|
||||
@ -1702,6 +1761,8 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
|
||||
attr->strokeLineCap = nsvg__parseLineCap(value);
|
||||
} else if (strcmp(name, "stroke-linejoin") == 0) {
|
||||
attr->strokeLineJoin = nsvg__parseLineJoin(value);
|
||||
} else if (strcmp(name, "stroke-miterlimit") == 0) {
|
||||
attr->miterLimit = nsvg__parseMiterLimit(value);
|
||||
} else if (strcmp(name, "fill-rule") == 0) {
|
||||
attr->fillRule = nsvg__parseFillRule(value);
|
||||
} else if (strcmp(name, "font-size") == 0) {
|
||||
@ -1718,19 +1779,7 @@ static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
|
||||
} else if (strcmp(name, "id") == 0) {
|
||||
strncpy(attr->id, value, 63);
|
||||
attr->id[63] = '\0';
|
||||
} else if (strcmp(name, "class") == 0) {
|
||||
NSVGstyles* style = p->styles;
|
||||
while (style) {
|
||||
if (strcmp(style->name + 1, value) == 0) {
|
||||
break;
|
||||
}
|
||||
style = style->next;
|
||||
}
|
||||
if (style) {
|
||||
nsvg__parseStyle(p, style->description);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@ -2030,7 +2079,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
|
||||
|
||||
rx = fabsf(args[0]); // y radius
|
||||
ry = fabsf(args[1]); // x radius
|
||||
rotx = args[2] / 180.0f * NSVG_PI; // x rotation engle
|
||||
rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle
|
||||
fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc
|
||||
fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction
|
||||
x1 = *cpx; // start point
|
||||
@ -2095,13 +2144,10 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
|
||||
// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
|
||||
// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
|
||||
|
||||
if (fa) {
|
||||
// Choose large arc
|
||||
if (da > 0.0f)
|
||||
da = da - 2*NSVG_PI;
|
||||
else
|
||||
da = 2*NSVG_PI + da;
|
||||
}
|
||||
if (fs == 0 && da > 0)
|
||||
da -= 2 * NSVG_PI;
|
||||
else if (fs == 1 && da < 0)
|
||||
da += 2 * NSVG_PI;
|
||||
|
||||
// Approximate the arc using cubic spline segments.
|
||||
t[0] = cosrx; t[1] = sinrx;
|
||||
@ -2117,7 +2163,7 @@ static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args,
|
||||
kappa = -kappa;
|
||||
|
||||
for (i = 0; i <= ndivs; i++) {
|
||||
a = a1 + da * (i/(float)ndivs);
|
||||
a = a1 + da * ((float)i/(float)ndivs);
|
||||
dx = cosf(a);
|
||||
dy = sinf(a);
|
||||
nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
|
||||
@ -2171,7 +2217,7 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr)
|
||||
if (!*item) break;
|
||||
if (nsvg__isnum(item[0])) {
|
||||
if (nargs < 10)
|
||||
args[nargs++] = (float)atof(item);
|
||||
args[nargs++] = (float)nsvg__atof(item);
|
||||
if (nargs >= rargs) {
|
||||
switch (cmd) {
|
||||
case 'm':
|
||||
@ -2428,7 +2474,7 @@ static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
|
||||
nargs = 0;
|
||||
while (*s) {
|
||||
s = nsvg__getNextPathItem(s, item);
|
||||
args[nargs++] = (float)atof(item);
|
||||
args[nargs++] = (float)nsvg__atof(item);
|
||||
if (nargs >= 2) {
|
||||
if (npts == 0)
|
||||
nsvg__moveTo(p, args[0], args[1]);
|
||||
@ -2453,11 +2499,26 @@ static void nsvg__parseSVG(NSVGparser* p, const char** attr)
|
||||
for (i = 0; attr[i]; i += 2) {
|
||||
if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
|
||||
if (strcmp(attr[i], "width") == 0) {
|
||||
p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
|
||||
p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
|
||||
} else if (strcmp(attr[i], "height") == 0) {
|
||||
p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f);
|
||||
p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f);
|
||||
} else if (strcmp(attr[i], "viewBox") == 0) {
|
||||
sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight);
|
||||
const char *s = attr[i + 1];
|
||||
char buf[64];
|
||||
s = nsvg__parseNumber(s, buf, 64);
|
||||
p->viewMinx = nsvg__atof(buf);
|
||||
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
|
||||
if (!*s) return;
|
||||
s = nsvg__parseNumber(s, buf, 64);
|
||||
p->viewMiny = nsvg__atof(buf);
|
||||
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
|
||||
if (!*s) return;
|
||||
s = nsvg__parseNumber(s, buf, 64);
|
||||
p->viewWidth = nsvg__atof(buf);
|
||||
while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++;
|
||||
if (!*s) return;
|
||||
s = nsvg__parseNumber(s, buf, 64);
|
||||
p->viewHeight = nsvg__atof(buf);
|
||||
} else if (strcmp(attr[i], "preserveAspectRatio") == 0) {
|
||||
if (strstr(attr[i + 1], "none") != 0) {
|
||||
// No uniform scaling
|
||||
@ -2658,8 +2719,6 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
||||
p->defsFlag = 1;
|
||||
} else if (strcmp(el, "svg") == 0) {
|
||||
nsvg__parseSVG(p, attr);
|
||||
} else if (strcmp(el, "style") == 0) {
|
||||
p->styleFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2673,76 +2732,13 @@ static void nsvg__endElement(void* ud, const char* el)
|
||||
p->pathFlag = 0;
|
||||
} else if (strcmp(el, "defs") == 0) {
|
||||
p->defsFlag = 0;
|
||||
} else if (strcmp(el, "style") == 0) {
|
||||
p->styleFlag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *nsvg__strndup(const char *s, size_t n)
|
||||
{
|
||||
char *result;
|
||||
size_t len = strlen(s);
|
||||
|
||||
if (n < len)
|
||||
len = n;
|
||||
|
||||
result = (char *)malloc(len + 1);
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
result[len] = '\0';
|
||||
return (char *)memcpy(result, s, len);
|
||||
}
|
||||
|
||||
static void nsvg__content(void* ud, const char* s)
|
||||
{
|
||||
NSVGparser* p = (NSVGparser*)ud;
|
||||
if (p->styleFlag) {
|
||||
|
||||
int state = 0;
|
||||
const char* start;
|
||||
while (*s) {
|
||||
char c = *s;
|
||||
if (nsvg__isspace(c) || c == '{') {
|
||||
if (state == 1) {
|
||||
NSVGstyles* next = p->styles;
|
||||
|
||||
p->styles = (NSVGstyles*)malloc(sizeof(NSVGstyles));
|
||||
p->styles->next = next;
|
||||
p->styles->name = nsvg__strndup(start, (size_t)(s - start));
|
||||
start = s + 1;
|
||||
state = 2;
|
||||
}
|
||||
} else if (state == 2 && c == '}') {
|
||||
p->styles->description = nsvg__strndup(start, (size_t)(s - start));
|
||||
state = 0;
|
||||
}
|
||||
else if (state == 0) {
|
||||
start = s;
|
||||
state = 1;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
// if (*s == '{' && state == NSVG_XML_CONTENT) {
|
||||
// // Start of a tag
|
||||
// *s++ = '\0';
|
||||
// nsvg__parseContent(mark, contentCb, ud);
|
||||
// mark = s;
|
||||
// state = NSVG_XML_TAG;
|
||||
// }
|
||||
// else if (*s == '>' && state == NSVG_XML_TAG) {
|
||||
// // Start of a content or new tag.
|
||||
// *s++ = '\0';
|
||||
// nsvg__parseElement(mark, startelCb, endelCb, ud);
|
||||
// mark = s;
|
||||
// state = NSVG_XML_CONTENT;
|
||||
// }
|
||||
// else {
|
||||
// s++;
|
||||
// }
|
||||
//}
|
||||
|
||||
}
|
||||
NSVG_NOTUSED(ud);
|
||||
NSVG_NOTUSED(s);
|
||||
// empty
|
||||
}
|
||||
|
||||
@ -2750,25 +2746,19 @@ static void nsvg__imageBounds(NSVGparser* p, float* bounds)
|
||||
{
|
||||
NSVGshape* shape;
|
||||
shape = p->image->shapes;
|
||||
int count = 0;
|
||||
|
||||
bounds[0] = FLT_MAX;
|
||||
bounds[1] = FLT_MAX;
|
||||
bounds[2] = -FLT_MAX;
|
||||
bounds[3] = -FLT_MAX;
|
||||
|
||||
for (; shape != NULL; shape = shape->next) {
|
||||
if ( (shape->flags & NSVG_FLAGS_VISIBLE) == NSVG_FLAGS_VISIBLE) {
|
||||
if (shape == NULL) {
|
||||
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
|
||||
return;
|
||||
}
|
||||
bounds[0] = shape->bounds[0];
|
||||
bounds[1] = shape->bounds[1];
|
||||
bounds[2] = shape->bounds[2];
|
||||
bounds[3] = shape->bounds[3];
|
||||
for (shape = shape->next; shape != NULL; shape = shape->next) {
|
||||
bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
|
||||
bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
|
||||
bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
|
||||
bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2784,12 +2774,12 @@ static float nsvg__viewAlign(float content, float container, int type)
|
||||
|
||||
static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy)
|
||||
{
|
||||
grad->xform[0] *= sx;
|
||||
grad->xform[1] *= sx;
|
||||
grad->xform[2] *= sy;
|
||||
grad->xform[3] *= sy;
|
||||
grad->xform[4] += tx*sx;
|
||||
grad->xform[5] += ty*sx;
|
||||
float t[6];
|
||||
nsvg__xformSetTranslation(t, tx, ty);
|
||||
nsvg__xformMultiply (grad->xform, t);
|
||||
|
||||
nsvg__xformSetScale(t, sx, sy);
|
||||
nsvg__xformMultiply (grad->xform, t);
|
||||
}
|
||||
|
||||
static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
|
||||
@ -2802,10 +2792,6 @@ static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
|
||||
|
||||
// Guess image size if not set completely.
|
||||
nsvg__imageBounds(p, bounds);
|
||||
// Patch: save real bounds.
|
||||
for (i = 0; i < 4; ++i) {
|
||||
p->image->realBounds[i] = bounds[i];
|
||||
}
|
||||
|
||||
if (p->viewWidth == 0) {
|
||||
if (p->image->width > 0) {
|
||||
@ -2940,6 +2926,36 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NSVGpath* nsvgDuplicatePath(NSVGpath* p)
|
||||
{
|
||||
NSVGpath* res = NULL;
|
||||
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
res = (NSVGpath*)malloc(sizeof(NSVGpath));
|
||||
if (res == NULL) goto error;
|
||||
memset(res, 0, sizeof(NSVGpath));
|
||||
|
||||
res->pts = (float*)malloc(p->npts*2*sizeof(float));
|
||||
if (res->pts == NULL) goto error;
|
||||
memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
|
||||
res->npts = p->npts;
|
||||
|
||||
memcpy(res->bounds, p->bounds, sizeof(p->bounds));
|
||||
|
||||
res->closed = p->closed;
|
||||
|
||||
return res;
|
||||
|
||||
error:
|
||||
if (res != NULL) {
|
||||
free(res->pts);
|
||||
free(res);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nsvgDelete(NSVGimage* image)
|
||||
{
|
||||
NSVGshape *snext, *shape;
|
||||
|
@ -98,7 +98,7 @@ public func addChannelMember(account: Account, peerId: PeerId, memberId: PeerId)
|
||||
return .fail(.tooMuchJoined)
|
||||
case "USERS_TOO_MUCH":
|
||||
return .fail(.limitExceeded)
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
case "USER_PRIVACY_RESTRICTED", "USER_NOT_MUTUAL_CONTACT":
|
||||
return .fail(.restricted)
|
||||
case "USER_BOT":
|
||||
return .fail(.bot(memberId))
|
||||
@ -194,7 +194,7 @@ public func addChannelMembers(account: Account, peerId: PeerId, memberIds: [Peer
|
||||
switch error.errorDescription {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
return .tooMuchJoined
|
||||
case "USER_PRIVACY_RESTRICTED":
|
||||
case "USER_PRIVACY_RESTRICTED", "USER_NOT_MUTUAL_CONTACT":
|
||||
return .restricted
|
||||
case "USERS_TOO_MUCH":
|
||||
return .limitExceeded
|
||||
|
@ -47,7 +47,7 @@ extension TelegramWallpaper {
|
||||
}
|
||||
self = .file(id: id, accessHash: accessHash, isCreator: (flags & 1 << 0) != 0, isDefault: (flags & 1 << 1) != 0, isPattern: (flags & 1 << 3) != 0, isDark: (flags & 1 << 4) != 0, slug: slug, file: file, settings: wallpaperSettings)
|
||||
} else {
|
||||
assertionFailure()
|
||||
//assertionFailure()
|
||||
self = .color(0xffffff)
|
||||
}
|
||||
case let .wallPaperNoFile(flags, settings):
|
||||
|
@ -21,6 +21,7 @@ import ImageBlur
|
||||
import TelegramAnimatedStickerNode
|
||||
import WallpaperResources
|
||||
import Svg
|
||||
import GZip
|
||||
|
||||
public func fetchCachedResourceRepresentation(account: Account, resource: MediaResource, representation: CachedMediaResourceRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
if let representation = representation as? CachedStickerAJpegRepresentation {
|
||||
@ -409,10 +410,14 @@ private func fetchCachedBlurredWallpaperRepresentation(resource: MediaResource,
|
||||
|
||||
private func fetchCachedPatternWallpaperMaskRepresentation(resource: MediaResource, resourceData: MediaResourceData, representation: CachedPatternWallpaperMaskRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
return Signal({ subscriber in
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) {
|
||||
if var data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) {
|
||||
let path = NSTemporaryDirectory() + "\(arc4random64())"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
|
||||
if let unzippedData = TGGUnzipData(data, 2 * 1024 * 1024) {
|
||||
data = unzippedData
|
||||
}
|
||||
|
||||
if data.count > 5, let string = String(data: data.subdata(in: 0 ..< 5), encoding: .utf8), string == "<?xml" {
|
||||
let size = representation.size ?? CGSize(width: 1440.0, height: 2960.0)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user