float RCTPathAddEllipticArc(IntPtr cr, IntPtr m, CGPoint origin, CGSize size, double startAngle, double endAngle, bool clockwise ) { float radius = 0; if (size.width != 0) { radius = size.width; } else if (size.height != 0) { radius = size.height; } Log.Info(ReactConstants.Tag, "[RCTPathAddEllipticArc] ReactBorderDrawingManager , radius:" + radius); Log.Info(ReactConstants.Tag, "[RCTPathAddEllipticArc] size.width:" + size.width + ", size.height:" + size.height); Log.Info(ReactConstants.Tag, "[RCTPathAddEllipticArc] origin.x:" + origin.x + ", origin.y:" + origin.y + ", startAngle:" + startAngle + ", endAngle:" + endAngle); // add a new arc path here in cairo context Cairo.cairo_arc(cr, origin.x, origin.y, radius, startAngle, endAngle); //Cairo.cairo_stroke(cairo); return(radius); }
void RCTContextSetFillColorWithUint(IntPtr cr, uint color) { uint b = color & 0xFF; uint g = (color >> 8) & 0xFF; uint r = (color >> 16) & 0xFF; Cairo.cairo_set_source_rgba(cairo, r, g, b, 1); //black alpha default }
void RCTContextAddLines(IntPtr cr, CGPoint[] points, int count) { Log.Info(ReactConstants.Tag, "[RCTContextAddLines] points[0].x:" + points[0].x + ", points[0].y:" + points[0].y + ", points[1].x:" + points[1].x + ", points[1].y:" + points[1].y); Log.Info(ReactConstants.Tag, "[RCTContextAddLines] points[2].x:" + points[2].x + ", points[2].y:" + points[2].y + ", points[3].x:" + points[3].x + ", points[3].y:" + points[3].y); Cairo.cairo_move_to(cairo, points[0].x, points[0].y); for (int n = 1; n < count; n++) { Cairo.cairo_line_to(cairo, points[n].x, points[n].y); } //Cairo.cairo_stroke(cairo); }
void RCTContextSaveCurrentImage() { // for temp test Cairo.cairo_surface_flush(surface); /* Save the generated cairo surface image data to PNG file from Memories */ string path = Tizen.Applications.Application.Current.DirectoryInfo.Data + "CairoBorder.png"; Cairo.cairo_surface_write_to_png(surface, path); pathImage = path; //return path; return; }
void RCTContextUpdateCurrentImage() { // for temp test Cairo.cairo_surface_flush(surface); /* display cairo drawin on screen */ img = Cairo.evas_object_image_filled_add(ReactProgram.RctWindow); IntPtr imageData = Cairo.cairo_image_surface_get_data(surface); Cairo.evas_object_image_data_set(img, imageData); Cairo.evas_object_image_data_update_add(img, 0, 0, 1920, 1080); return; }
public void RCTUIGraphicsBeginImageContext(CGSize size, Color backgroundColor, bool hasCornerRadii, bool drawToEdge) { /// create cairo surface and context here surface = Cairo.cairo_image_surface_create(0, 1920, 1080); cairo = Cairo.cairo_create(surface); /* clear background as white */ Cairo.cairo_set_source_rgba(cairo, 1, 1, 1, 1); Cairo.cairo_paint(cairo); // set default stroke line width and color for Cairo context Cairo.cairo_set_line_width(cairo, 1.0); Cairo.cairo_set_source_rgba(cairo, 0, 0, 0, 1); //black line }
void RCTPathCreateOuterOutline(bool drawToEdge, CGRect rect, RCTCornerRadii cornerRadii) { if (drawToEdge) { Log.Info(ReactConstants.Tag, "[RCTPathCreateOuterOutline] ReactBorderDrawingManager , cairo:" + cairo); Log.Info(ReactConstants.Tag, "[RCTPathCreateOuterOutline] rect.origin.x:" + rect.origin.x + ", rect.origin.y:" + rect.origin.y + ", rect.size.width:" + rect.size.width + ", rect.size.height:" + rect.size.height); // add a new rectangle path here in cairo context Cairo.cairo_rectangle(cairo, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height); pathOuter = Cairo.cairo_copy_path(cairo); //Cairo.cairo_stroke(cairo); return; } //RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, new UIEdgeInsets(0,0,0,0))); pathOuter = RCTPathCreateWithRoundedRect(rect, RCTGetCornerInsets(cornerRadii, new UIEdgeInsets(0, 0, 0, 0))); }
void RCTGetSolidBorderImage(RCTCornerRadii cornerRadii, CGSize viewSize, UIEdgeInsets borderInsets, RCTBorderColors borderColors, //uint backgroundColor, Color backgroundColor, bool drawToEdge) { bool hasCornerRadii = RCTCornerRadiiAreAboveThreshold(cornerRadii); RCTCornerInsets cornerInsets = RCTGetCornerInsets(cornerRadii, borderInsets); Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager::RCTGetSolidBorderImage BGN "); Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager , hasCornerRadii:" + hasCornerRadii); bool makeStretchable = (borderInsets.left + cornerInsets.topLeft.width + borderInsets.right + cornerInsets.bottomRight.width <= viewSize.width) && (borderInsets.left + cornerInsets.bottomLeft.width + borderInsets.right + cornerInsets.topRight.width <= viewSize.width) && (borderInsets.top + cornerInsets.topLeft.height + borderInsets.bottom + cornerInsets.bottomRight.height <= viewSize.height) && (borderInsets.top + cornerInsets.topRight.height + borderInsets.bottom + cornerInsets.bottomLeft.height <= viewSize.height); UIEdgeInsets edgeInsets = new UIEdgeInsets ( borderInsets.top + Math.Max(cornerInsets.topLeft.height, cornerInsets.topRight.height), borderInsets.left + Math.Max(cornerInsets.topLeft.width, cornerInsets.bottomLeft.width), borderInsets.bottom + Math.Max(cornerInsets.bottomLeft.height, cornerInsets.bottomRight.height), borderInsets.right + Math.Max(cornerInsets.bottomRight.width, cornerInsets.topRight.width) ); makeStretchable = false; Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager , makeStretchable:" + makeStretchable); CGSize sizeStretch = new CGSize ( // 1pt for the middle stretchable area along each axis edgeInsets.left + 1 + edgeInsets.right, edgeInsets.top + 1 + edgeInsets.bottom ); //CGSize size = makeStretchable ? sizeStretch: viewSize; CGSize size = viewSize; // begin libCairo engine drawing context RCTUIGraphicsBeginImageContext(size, backgroundColor, hasCornerRadii, drawToEdge); CGRect rect = new CGRect((new CGPoint(0, 0)), size); RCTPathCreateOuterOutline(drawToEdge, rect, cornerRadii); Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager , backgroundColor.IsDefault:" + backgroundColor.IsDefault); if (!backgroundColor.IsDefault) { // paint the background color here Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager::Fill the background Color! "); RCTContextSetFillColorWithColor(cairo, backgroundColor); //RCTContextSetFillColorWithUint(cairo, backgroundColor); Cairo.cairo_fill(cairo); } // for Cairo instead, draw rounded Rectangle path here Cairo.cairo_append_path(cairo, pathOuter); pathInner = RCTPathCreateWithRoundedRect(UIEdgeInsetsInsetRect(rect, borderInsets), cornerInsets); //Cairo.cairo_append_path(cairo, pathInner); /// Clip the outerpath with inner path by eod rule.. Cairo.cairo_set_fill_rule(cairo, Cairo.cairo_fill_rule_t.CAIRO_FILL_RULE_EVEN_ODD); //Cairo.cairo_set_fill_rule(cairo, Cairo.cairo_fill_rule_t.CAIRO_FILL_RULE_WINDING); Cairo.cairo_clip(cairo); RCTContextSetFillColorWithUint(cairo, borderColors.left); Cairo.cairo_paint(cairo); bool hasEqualColors = RCTBorderColorsAreEqual(borderColors); Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] drawToEdge:" + drawToEdge + ", hasCornerRadii:" + hasCornerRadii + ", hasEqualColors:" + hasEqualColors); if ((drawToEdge || !hasCornerRadii) && hasEqualColors) { Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] rect.origin.x:" + rect.origin.x + ", rect.origin.y:" + rect.origin.y + ", rect.size.width:" + rect.size.width + ", rect.size.height:" + rect.size.height); RCTContextSetFillColorWithUint(cairo, borderColors.left); Cairo.cairo_paint(cairo); } else { if ((hasCornerRadii)) { Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager-->not support different color for rounded rectangle! "); RCTContextSaveCurrentImage(); return; } CGPoint topLeft = new CGPoint(borderInsets.left, borderInsets.top); if (cornerInsets.topLeft.width > 0 && cornerInsets.topLeft.height > 0) { CGPoint[] points = new CGPoint[2]; CGRect tl = new CGRect ( topLeft, new CGSize(2 * cornerInsets.topLeft.width, 2 * cornerInsets.topLeft.height) ); RCTEllipseGetIntersectionsWithLine(tl, CGPointZero, topLeft, points); if (!Single.IsNaN(points[1].x) && !Single.IsNaN(points[1].y)) { topLeft = points[1]; } } CGPoint bottomLeft = new CGPoint(borderInsets.left, size.height - borderInsets.bottom); if (cornerInsets.bottomLeft.width > 0 && cornerInsets.bottomLeft.height > 0) { CGPoint[] points = new CGPoint[2]; CGRect bl = new CGRect ( new CGPoint(bottomLeft.x, bottomLeft.y - 2 * cornerInsets.bottomLeft.height), new CGSize(2 * cornerInsets.bottomLeft.width, 2 * cornerInsets.bottomLeft.height) ); CGPoint ble = new CGPoint(0, size.height); RCTEllipseGetIntersectionsWithLine(bl, ble, bottomLeft, points); if (!Single.IsNaN(points[1].x) && !Single.IsNaN(points[1].y)) { bottomLeft = points[1]; } } CGPoint topRight = new CGPoint(size.width - borderInsets.right, borderInsets.top); if (cornerInsets.topRight.width > 0 && cornerInsets.topRight.height > 0) { CGPoint[] points = new CGPoint[2]; CGRect tr = new CGRect ( new CGPoint(topRight.x - 2 * cornerInsets.topRight.width, topRight.y), new CGSize(2 * cornerInsets.topRight.width, 2 * cornerInsets.topRight.height) ); CGPoint tre = new CGPoint(size.width, 0); RCTEllipseGetIntersectionsWithLine(tr, tre, topRight, points); if (!Single.IsNaN(points[0].x) && !Single.IsNaN(points[0].y)) { topRight = points[0]; } } CGPoint bottomRight = new CGPoint(size.width - borderInsets.right, size.height - borderInsets.bottom); if (cornerInsets.bottomRight.width > 0 && cornerInsets.bottomRight.height > 0) { CGPoint[] points = new CGPoint[2]; CGRect br = new CGRect ( new CGPoint(bottomRight.x - 2 * cornerInsets.bottomRight.width, bottomRight.y - 2 * cornerInsets.bottomRight.height), new CGSize(2 * cornerInsets.bottomRight.width, 2 * cornerInsets.bottomRight.height) ); CGPoint bre = new CGPoint(size.width, size.height); RCTEllipseGetIntersectionsWithLine(br, bre, bottomRight, points); if (!Single.IsNaN(points[0].x) && !Single.IsNaN(points[0].y)) { bottomRight = points[0]; } } Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] ReactBorderDrawingManager::RCTGetSolidBorderImage BGN Draw each colored Edge!"); Log.Info(ReactConstants.Tag, "[RCTGetSolidBorderImage] borderInsets.right:" + borderInsets.right + ", borderInsets.bottom:" + borderInsets.bottom + ", borderInsets.left:" + borderInsets.left + ", borderInsets.top:" + borderInsets.top); uint currentColor = 0; //Cairo.cairo_set_fill_rule(cairo, Cairo.cairo_fill_rule_t.CAIRO_FILL_RULE_WINDING); // RIGHT if (borderInsets.right > 0) { CGPoint[] points = { new CGPoint(size.width, 0), topRight, bottomRight, new CGPoint(size.width, size.height), }; currentColor = borderColors.right; RCTContextAddLines(cairo, points, 4); } // BOTTOM if (borderInsets.bottom > 0) { CGPoint[] points = { new CGPoint(0, size.height), bottomLeft, bottomRight, new CGPoint(size.width, size.height), }; if (!(currentColor == borderColors.bottom)) { RCTContextSetFillColorWithUint(cairo, currentColor); Cairo.cairo_fill(cairo); currentColor = borderColors.bottom; } RCTContextAddLines(cairo, points, 4); } // LEFT if (borderInsets.left > 0) { CGPoint[] points = { CGPointZero, topLeft, bottomLeft, new CGPoint(0,size.height), }; if (!(currentColor == borderColors.left)) { RCTContextSetFillColorWithUint(cairo, currentColor); Cairo.cairo_fill(cairo); currentColor = borderColors.left; } RCTContextAddLines(cairo, points, 4); } // TOP if (borderInsets.top > 0) { CGPoint[] points = { CGPointZero, topLeft, topRight, new CGPoint(size.width, 0), }; if (!(currentColor == borderColors.top)) { RCTContextSetFillColorWithUint(cairo, currentColor); Cairo.cairo_fill(cairo); currentColor = borderColors.top; } RCTContextAddLines(cairo, points, 4); } RCTContextSetFillColorWithUint(cairo, currentColor); Cairo.cairo_fill(cairo); } RCTContextSaveCurrentImage(); return; }
void RCTContextSetFillColorWithColor(IntPtr cr, Color color) { // set with Color parsed value Cairo.cairo_set_source_rgba(cairo, color.R, color.G, color.B, color.A); }
IntPtr RCTPathCreateWithRoundedRect(CGRect bounds, RCTCornerInsets cornerInsets ) { Log.Info(ReactConstants.Tag, "[RCTPathCreateWithRoundedRect] ReactBorderDrawingManager::RCTPathCreateWithRoundedRect BGN "); Log.Info(ReactConstants.Tag, "[RCTPathCreateWithRoundedRect] bounds.origin.x:" + bounds.origin.x + ", bounds.origin.y:" + bounds.origin.y + ", bounds.size.width:" + bounds.size.width + ", bounds.size.height:" + bounds.size.height); float minX = RectGetMinX(bounds); float minY = RectGetMinY(bounds); float maxX = RectGetMaxX(bounds); float maxY = RectGetMaxY(bounds); CGSize topLeft = new CGSize ( Math.Max(0, Math.Min(cornerInsets.topLeft.width, bounds.size.width - cornerInsets.topRight.width)), Math.Max(0, Math.Min(cornerInsets.topLeft.height, bounds.size.height - cornerInsets.bottomLeft.height)) ); CGSize topRight = new CGSize ( Math.Max(0, Math.Min(cornerInsets.topRight.width, bounds.size.width - cornerInsets.topLeft.width)), Math.Max(0, Math.Min(cornerInsets.topRight.height, bounds.size.height - cornerInsets.bottomRight.height)) ); CGSize bottomLeft = new CGSize ( Math.Max(0, Math.Min(cornerInsets.bottomLeft.width, bounds.size.width - cornerInsets.bottomRight.width)), Math.Max(0, Math.Min(cornerInsets.bottomLeft.height, bounds.size.height - cornerInsets.topLeft.height)) ); CGSize bottomRight = new CGSize ( Math.Max(0, Math.Min(cornerInsets.bottomRight.width, bounds.size.width - cornerInsets.bottomLeft.width)), Math.Max(0, Math.Min(cornerInsets.bottomRight.height, bounds.size.height - cornerInsets.topRight.height)) ); CGPoint p1 = new CGPoint ( minX + topLeft.width, minY + topLeft.height ); CGPoint p2 = new CGPoint ( maxX - topRight.width, minY + topRight.height ); CGPoint p3 = new CGPoint ( maxX - bottomRight.width, maxY - bottomRight.height ); CGPoint p4 = new CGPoint ( minX + bottomLeft.width, maxY - bottomLeft.height ); // begin a new cairo drawing path without current point Cairo.cairo_new_sub_path(cairo); RCTPathAddEllipticArc(cairo, IntPtr.Zero, p1, topLeft, Math.PI, 3 * Math.PI / 2, false); RCTPathAddEllipticArc(cairo, IntPtr.Zero, p2, topRight, 3 * Math.PI / 2, 0, false); RCTPathAddEllipticArc(cairo, IntPtr.Zero, p3, bottomRight, 0, Math.PI / 2, false); RCTPathAddEllipticArc(cairo, IntPtr.Zero, p4, bottomLeft, Math.PI / 2, Math.PI, false); /// auto close the current by draw a line to the init point Cairo.cairo_close_path(cairo); IntPtr path = Cairo.cairo_copy_path(cairo); //Cairo.cairo_stroke(cairo); return(path); }