// RUN: %target-swift-frontend -target x86_64-apple-macosx10.11 -module-name=cgtest -emit-ir -O %s | %FileCheck %s

// Test some imported CG APIs
import CoreGraphics

// REQUIRES: OS=macosx

// CHECK: [[SWITCHTABLE:@.*]] = private unnamed_addr constant [8 x i64] [i64 0, i64 12, i64 23, i64 34, i64 45, i64 55, i64 67, i64 71]

// CHECK-LABEL: define swiftcc i64 {{.*}}testEnums{{.*}} {
public func testEnums(_ model: CGColorSpaceModel) -> Int {
  switch model {
     case .unknown : return 0
     case .monochrome : return 12
     case .rgb : return 23
     case .cmyk : return 34
     case .lab : return 45
     case .deviceN : return 55
     case .indexed : return 67
     case .pattern : return 71

     default: return 0
  }
// CHECK:   [[GEP:%.+]] = getelementptr inbounds [8 x i64], [8 x i64]* [[SWITCHTABLE]], i64 0, i64 %{{.*}}
// CHECK:   [[LOAD:%.+]] = load i64, i64* [[GEP]], align 8
// CHECK:   ret i64 [[LOAD]]
}

// CHECK-LABEL: define swiftcc void {{.*}}rotationAround{{.*}} {
// Get a transform that will rotate around a given offset
public func rotationAround(offset: CGPoint, angle: CGFloat,
        transform: CGAffineTransform = .identity) -> CGAffineTransform {
  // FIXME: consistent API namings
  return transform.translatedBy(x: offset.x, y: offset.y)
                  .rotated(by: angle)
                  .translatedBy(x: -offset.x, y: -offset.y)

// CHECK:   call void @CGAffineTransformTranslate(%{{.*}}.CGAffineTransform* {{.*}}, %{{.*}}.CGAffineTransform* {{.*}},{{.*}}, {{.*}})
// CHECK:   call void @CGAffineTransformRotate(%{{.*}}.CGAffineTransform* {{.*}}, %{{.*}}.CGAffineTransform* {{.*}},{{.*}})
// CHECK:   call void @CGAffineTransformTranslate(%{{.*}}.CGAffineTransform* {{.*}}, %{{.*}}.CGAffineTransform* {{.*}},{{.*}}, {{.*}})
//
// CHECK:   ret void
}

// CHECK-LABEL: define swiftcc void {{.*}}trace{{.*}} {
public func trace(in context: CGContext, path: CGPath) {
  let red = CGColor(red: 1, green: 0, blue: 0, alpha: 1)
  context.saveGState()
  context.addPath(path)
  context.setStrokeColor(red)
  context.strokePath()
  context.restoreGState()
// CHECK:   call %{{.*}}.CGColor* @CGColorCreateGenericRGB(double 1.000000e+00, double 0.000000e+00, double 0.000000e+00, double 1.000000e+00)
// CHECK:   call void @CGContextSaveGState(%{{.*}}.CGContext* %{{.*}})
// CHECK:   call void @CGContextAddPath(%{{.*}}.CGContext* %{{.*}}, %{{.*}}.CGPath* %{{.*}})
// CHECK:   call void @CGContextSetStrokeColorWithColor(%{{.*}}.CGContext* %{{.*}}, %{{.*}}.CGColor* %{{.*}})
// CHECK:   call void @CGContextStrokePath(%{{.*}}.CGContext* %{{.*}})
// CHECK:   call void @CGContextRestoreGState(%{{.*}}.CGContext* %{{.*}})
//
// CHECK:   ret void
}

// CHECK-LABEL: define swiftcc void {{.*}}pdfOperations{{.*}} {
public func pdfOperations(_ context: CGContext) {
	context.beginPDFPage(nil)
	context.endPDFPage()
	context.closePDF()
// CHECK:   call void @CGPDFContextBeginPage(%{{.*}}.CGContext* %{{.*}}, %{{.*}}.__CFDictionary* {{.*}})
// CHECK:   call void @CGPDFContextEndPage(%{{.*}}.CGContext* %{{.*}})
// CHECK:   call void @CGPDFContextClose(%{{.*}}.CGContext* %{{.*}})
//
// CHECK:   ret void
}

// Test some more recently renamed APIs

// CHECK-LABEL: define swiftcc void {{.*}}testColorRenames{{.*}} {
public func testColorRenames(color: CGColor,
                             intent: CGColorRenderingIntent) {
  let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)!
// CHECK:   %{{.*}} = load {{.*}}%struct.__CFString** @kCGColorSpaceSRGB{{.*}}, align 8
// CHECK:   %{{.*}} = {{.*}} call %struct.CGColorSpace* @CGColorSpaceCreateWithName(%struct.__CFString* %{{.*}})

  let _ = color.converted(to: colorSpace, intent: intent, options: nil)
// CHECK:   %{{.*}} = {{.*}} call %struct.CGColor* @CGColorCreateCopyByMatchingToColorSpace(%struct.CGColorSpace* nonnull %{{.*}}, i32 %{{.*}}, %struct.CGColor* %{{.*}}, %struct.__CFDictionary* null)
//
// CHECK:   ret void
}

// CHECK-LABEL: define swiftcc void {{.*}}testRenames{{.*}} {
public func testRenames(transform: CGAffineTransform, context: CGContext,
                        point: CGPoint, size: CGSize, rect: CGRect,
                        image: CGImage,
                        edge: CGRectEdge) {
  let transform = transform.inverted().concatenating(transform)
// CHECK:   call void @CGAffineTransformInvert(%struct.CGAffineTransform* {{.*}}, %struct.CGAffineTransform* {{.*}})
// CHECK:   call void @CGAffineTransformConcat(%struct.CGAffineTransform* {{.*}}, %struct.CGAffineTransform* {{.*}}, %struct.CGAffineTransform* {{.*}})

  let _ = point.applying(transform)
  var rect = rect.applying(transform)
  let _ = size.applying(transform)
// CHECK:   %{{.*}} = call { double, double } @CGPointApplyAffineTransform(double %{{.*}}, double %{{.*}}, %struct.CGAffineTransform* {{.*}})
// CHECK:   call void @CGRectApplyAffineTransform(%struct.CGRect* {{.*}}, %struct.CGRect* {{.*}}, %struct.CGAffineTransform* {{.*}})
// CHECK:   %{{.*}} = call { double, double } @CGSizeApplyAffineTransform(double %{{.*}}, double %{{.*}}, %struct.CGAffineTransform* {{.*}})

  context.concatenate(transform)
  context.rotate(by: CGFloat.pi)
  context.scaleBy(x: 1.0, y: 1.0)
  context.translateBy(x: 1.0, y: 1.0)
// CHECK:   call void @CGContextConcatCTM(%struct.CGContext* [[CONTEXT:%[0-9]+]], %struct.CGAffineTransform* {{.*}})
// CHECK:   call void @CGContextRotateCTM(%struct.CGContext* [[CONTEXT]], double {{.*}})
// CHECK:   call void @CGContextScaleCTM(%struct.CGContext* [[CONTEXT]], double {{1\.0+.*}}, double {{1\.0+.*}})
// CHECK:   call void @CGContextTranslateCTM(%struct.CGContext* [[CONTEXT]], double {{1\.0+.*}}, double {{1\.0+.*}})

  context.clip(to: rect)
  context.clip(to: rect, mask: image)
// CHECK:   call void @CGContextClipToRect(%struct.CGContext* [[CONTEXT]], %struct.CGRect* byval nonnull align 8 %{{.*}})
// CHECK:   call void @CGContextClipToMask(%struct.CGContext* [[CONTEXT]], %struct.CGRect* byval nonnull align 8 %{{.*}}, %struct.CGImage* %{{.*}})

  var slice = CGRect.zero
  var remainder = CGRect.zero
  rect.__divided(slice: &slice, remainder: &remainder, atDistance: CGFloat(2.0),
          from: edge)
  assert((slice, remainder) == rect.divided(atDistance: CGFloat(2.0),
                                            from: edge))
// CHECK:   call void @CGRectDivide(%struct.CGRect* byval nonnull align 8 %{{.*}}, %struct.CGRect* nonnull %{{.*}}, %struct.CGRect* nonnull %{{.*}}, double {{2\.0+.*}}, i32 %{{.*}})
//
// CHECK:   ret void
}

