void JBGStrokePathByLines(CGContextRef ctx, CGPathRef path, CGColorRef color_1, CGFloat width_1, CGColorRef color_2, CGFloat width_2, CGColorRef color_3, CGFloat width_3) { if (width_1 > 0.0f) { CGContextSetLineWidth(ctx, width_1); CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_1); CGContextStrokePath(ctx); } if (width_2 > 0.0f) { CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_2); CGContextSetLineWidth(ctx, width_2); CGContextStrokePath(ctx); } if (width_3 > 0.0f) { CGContextAddPath(ctx, path); CGContextSetStrokeColorWithColor(ctx, color_3); CGContextSetLineWidth(ctx, width_3); CGContextStrokePath(ctx); } }
void doStrokeWithCTM(CGContextRef context) { CGContextTranslateCTM(context, 150., 180.); CGContextSetLineWidth(context, 10); // Draw ellipse 1 with a uniform stroke. CGContextSaveGState(context); // Scale the CTM so the circular arc will be elliptical. CGContextScaleCTM(context, 2, 1); CGContextBeginPath(context); // Create an arc that is a circle. CGContextAddArc(context, 0., 0., 45., 0., 2*M_PI, 0); // Restore the context parameters prior to stroking the path. // CGContextRestoreGState does not affect the path in the context. CGContextRestoreGState(context); CGContextStrokePath(context); // *** was 0, -120 CGContextTranslateCTM(context, 220., 0.); // Draw ellipse 2 with non-uniform stroke. CGContextSaveGState(context); // Scale the CTM so the circular arc will be elliptical. CGContextScaleCTM(context, 2, 1); CGContextBeginPath(context); // Create an arc that is a circle. CGContextAddArc(context, 0., 0., 45., 0., 2*M_PI, 0); // Stroke the path with the scaled coordinate system in effect. CGContextStrokePath(context); CGContextRestoreGState(context); }
//----------------------------------------------------------------------------------- static void DrawTheMTView(CGContextRef ctx, MTViewData* data) { CGRect dstRect; #if CG_COORDINATES TransformHIViewToCG(ctx, data->theView); #endif // Draw the image first, before stroking the path; otherwise the path gets overwritten if (data->theImage != NULL) { dstRect = CGRectMake(0, 0, CGImageGetWidth(data->theImage), CGImageGetHeight(data->theImage)); #if CG_COORDINATES CGContextDrawImage(ctx, dstRect, data->theImage); #else HIViewDrawCGImage(ctx, &dstRect, data->theImage); #endif } if (data->thePath != NULL) { CGPathApply(data->thePath, (void*)ctx, MyCGPathApplier); CGContextStrokePath(ctx); } } // DrawTheMTView
void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) { if (paintingDisabled()) return; if (npoints <= 1) return; CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextSetShouldAntialias(context, shouldAntialias); CGContextBeginPath(context); CGContextMoveToPoint(context, points[0].x(), points[0].y()); for (size_t i = 1; i < npoints; i++) CGContextAddLineToPoint(context, points[i].x(), points[i].y()); CGContextClosePath(context); if (fillColor().alpha()) CGContextEOFillPath(context); if (strokeStyle() != NoStroke) CGContextStrokePath(context); CGContextRestoreGState(context); }
// This method is only used to draw the little circles used in lists. void GraphicsContext::drawEllipse(const IntRect& rect) { // FIXME: CG added CGContextAddEllipseinRect in Tiger, so we should be able to quite easily draw an ellipse. // This code can only handle circles, not ellipses. But khtml only // uses it for circles. ASSERT(rect.width() == rect.height()); if (paintingDisabled()) return; CGContextRef context = platformContext(); CGContextBeginPath(context); float r = (float)rect.width() / 2; CGContextAddArc(context, rect.x() + r, rect.y() + r, r, 0, 2*M_PI, true); CGContextClosePath(context); if (fillColor().alpha()) { if (strokeStyle() != NoStroke) // stroke and fill CGContextDrawPath(context, kCGPathFillStroke); else CGContextFillPath(context); } else if (strokeStyle() != NoStroke) CGContextStrokePath(context); }
static void Quartz_Circle(double x, double y, double r, R_GE_gcontext *gc, NewDevDesc *dd) { QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific; CGContextSaveGState( GetContext(xd) ); CGContextBeginPath( GetContext(xd) ); Quartz_SetLineProperties(gc, dd); CGContextAddArc( GetContext(xd), (float)x , (float)y, (float)r, 3.141592654 * 2.0, 0.0, 0); Quartz_SetFill( gc->fill, gc->gamma, dd); CGContextFillPath( GetContext(xd) ); Quartz_SetStroke( gc->col, gc->gamma, dd); CGContextAddArc( GetContext(xd), (float)x , (float)y, (float)r, 3.141592654 * 2.0, 0.0, 0); CGContextStrokePath( GetContext(xd) ); CGContextRestoreGState( GetContext(xd) ); }
static void Quartz_Polyline(int n, double *x, double *y, R_GE_gcontext *gc, NewDevDesc *dd) { CGPoint *lines; int i; CGrafPtr savedPort, port; QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific; lines = (CGPoint *)malloc(sizeof(CGPoint)*n); if(lines == NULL) return; for (i = 0; i < n; i++) { lines[i].x = (float)x[i]; lines[i].y = (float)y[i]; } CGContextSaveGState( GetContext(xd) ); CGContextBeginPath( GetContext(xd) ); Quartz_SetLineProperties(gc, dd); CGContextAddLines( GetContext(xd), &lines[0], n ); Quartz_SetStroke( gc->col, gc->gamma, dd); CGContextStrokePath( GetContext(xd) ); CGContextRestoreGState( GetContext(xd) ); }
static void Quartz_Line(double x1, double y1, double x2, double y2, R_GE_gcontext *gc, NewDevDesc *dd) { QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific; CGPoint lines[ 2 ]; Rect rect; CGContextSaveGState( GetContext(xd) ); CGContextBeginPath( GetContext(xd) ); lines[0].x = (float)x1; lines[0].y = (float)y1; lines[1].x = (float)x2; lines[1].y = (float)y2; Quartz_SetLineProperties(gc, dd); CGContextAddLines( GetContext(xd), &lines[0], 2 ); Quartz_SetStroke( gc->col, gc->gamma, dd); CGContextStrokePath( GetContext(xd) ); CGContextRestoreGState( GetContext(xd) ); }
FX_BOOL CFX_QuartzDeviceDriver::DrawCosmeticLine(FX_FLOAT x1, FX_FLOAT y1, FX_FLOAT x2, FX_FLOAT y2, FX_DWORD argb, int alphaFlag , void* iccTransform , int blend_type ) { CGBlendMode mode = GetCGBlendMode(blend_type); if (mode != kCGBlendModeNormal) { CGContextSetBlendMode(_context, mode); } CGPoint pt = CGPointApplyAffineTransform(CGPointMake(x1, y1), _foxitDevice2User); x1 = pt.x; y1 = pt.y; pt = CGPointApplyAffineTransform(CGPointMake(x2, y2), _foxitDevice2User); x2 = pt.x; y2 = pt.y; FX_INT32 a, r, g, b; ArgbDecode(argb, a, r, g, b); CGContextSetRGBStrokeColor(_context, r / 255.f, g / 255.f, b / 255.f, a / 255.f); CGContextMoveToPoint(_context, x1, y1); CGContextAddLineToPoint(_context, x2, y2); CGContextStrokePath(_context); if (mode != kCGBlendModeNormal) { CGContextSetBlendMode(_context, kCGBlendModeNormal); } return TRUE; }
void MacVegaPrinterListener::DrawEllipse(const OpRect& rect, UINT32 width) { CGRect cgrect = CGRectMake(rect.x, rect.y, rect.width, rect.height); cgrect.origin.y = m_winHeight - cgrect.origin.y - cgrect.size.height; float cx = cgrect.origin.x + (cgrect.size.width / 2); float cy = cgrect.origin.y + (cgrect.size.height / 2); float radius = cgrect.size.width / 2; if(width != 1) { CGContextSetLineWidth(m_ctx, width); } if(cgrect.size.width != cgrect.size.height) { cy = cy * cgrect.size.width / cgrect.size.height; CGContextScaleCTM(m_ctx, 1.0, cgrect.size.height/cgrect.size.width); } CGContextAddArc(m_ctx, cx, cy, radius, 0, 2*M_PI, 0); CGContextStrokePath(m_ctx); if(width != 1) { CGContextSetLineWidth(m_ctx, 1); } if(cgrect.size.width != cgrect.size.height) { CGContextScaleCTM(m_ctx, 1.0, cgrect.size.width/cgrect.size.height); } }
void doPixelAlignedFillAndStroke(CGContextRef context) { CGPoint p1 = CGPointMake(16.7, 17.8); CGPoint p2 = CGPointMake(116.7, 17.8); CGRect r = CGRectMake(16.7, 20.8, 100.6, 100.6); CGSize s; CGContextSetLineWidth(context, 2); CGContextSetRGBFillColor(context, 1., 0., 0., 1.); CGContextSetRGBStrokeColor(context, 1., 0., 0., 1.); // Unaligned drawing. CGContextBeginPath(context); CGContextMoveToPoint(context, p1.x, p1.y); CGContextAddLineToPoint(context, p2.x, p2.y); CGContextStrokePath(context); CGContextFillRect(context, r); // Translate to the right before drawing along // aligned coordinates. CGContextTranslateCTM(context, 106, 0); // Aligned drawing. // Compute the length of the line in user space. s = CGSizeMake(p2.x - p1.x, p2.y - p1.y); CGContextBeginPath(context); // Align the starting point to a device // pixel boundary. p1 = alignPointToUserSpace(context, p1); // Establish the starting point of the line. CGContextMoveToPoint(context, p1.x, p1.y); // Compute the line length as an integer // number of device pixels. s = alignSizeToUserSpace(context, s); CGContextAddLineToPoint(context, p1.x + s.width, p1.y + s.height); CGContextStrokePath(context); // Compute a rect that is aligned to device // space with a width that is an integer // number of device pixels. r = alignRectToUserSpace(context, r); CGContextFillRect(context, r); }
/* frameOval : Draws an outline of an oval just inside the bounding rectangle that you specify. Parameter Descriptions context : The CG context to render to. r : The CG rectangle that defines the ovalÕs boundary. */ void frameOval(CGContextRef context, CGRect r) { // Add a path for the oval to this context addOvalToPath(context,r); // Stroke the path CGContextStrokePath(context); }
FX_BOOL CFX_QuartzDeviceDriver::DrawPath(const CFX_PathData* pathData, const CFX_AffineMatrix* matrix, const CFX_GraphStateData* graphState, FX_DWORD fillArgb, FX_DWORD strokeArgb, int fillMode, int alpha_flag, void* pIccTransform, int blend_type ) { SaveState(); CGBlendMode mode = GetCGBlendMode(blend_type); if (mode != kCGBlendModeNormal) { CGContextSetBlendMode(_context, mode); } CGAffineTransform m = CGAffineTransformIdentity; if (matrix) { m = CGAffineTransformMake(matrix->GetA(), matrix->GetB(), matrix->GetC(), matrix->GetD(), matrix->GetE(), matrix->GetF()); } m = CGAffineTransformConcat(m, _foxitDevice2User); CGContextConcatCTM(_context, m); int pathMode = 0; if (graphState && strokeArgb) { CGContextSetMiterLimit(_context, graphState->m_MiterLimit); FX_FLOAT lineWidth = getLineWidth(graphState, m); setStrokeInfo(graphState, strokeArgb, lineWidth); pathMode |= 4; } if (fillMode && fillArgb) { setFillInfo(fillArgb); if ((fillMode & 3) == FXFILL_WINDING) { pathMode |= 1; } else if ((fillMode & 3) == FXFILL_ALTERNATE) { pathMode |= 2; } } setPathToContext(pathData); if (fillMode & FXFILL_FULLCOVER) { CGContextSetShouldAntialias(_context, false); } if (pathMode == 4) { CGContextStrokePath(_context); } else if (pathMode == 1) { CGContextFillPath(_context); } else if (pathMode == 2) { CGContextEOFillPath(_context); } else if (pathMode == 5) { CGContextDrawPath(_context, kCGPathFillStroke); } else if (pathMode == 6) { CGContextDrawPath(_context, kCGPathEOFillStroke); } RestoreState(FALSE); return TRUE; }
/* strokeRoundedRect : Draws a rounded rectangle with the current stroke color Parameter Descriptions rect : The CG rectangle that defines the rectangle's boundary. ovalWidth : The width of the CG rectangle that encloses the rounded corners ovalHeight : The height of the CG rectangle that encloses the rounded corners context : The CG context to render to. */ void strokeRoundedRect(CGContextRef context, CGRect rect, float ovalWidth, float ovalHeight) { // Signal the start of a path CGContextBeginPath(context); // Add a rounded rect to the path addRoundedRectToPath(context, rect, ovalWidth, ovalHeight); // Stroke the path CGContextStrokePath(context); }
void frameArc(CGContextRef context, CGRect r, int startAngle, int arcAngle) { // Signal the start of a path CGContextBeginPath(context); // Add to the path the arc of the oval that fits inside the rectangle. pathForArc(context,r,startAngle,arcAngle); // Stroke the path CGContextStrokePath(context); }
bool GiCanvasIos::rawLine(const GiContext* ctx, float x1, float y1, float x2, float y2) { bool ret = m_draw->setPen(ctx); if (ret) { CGContextMoveToPoint(m_draw->getContext(), x1, y1); CGContextAddLineToPoint(m_draw->getContext(), x2, y2); CGContextStrokePath(m_draw->getContext()); } return ret; }
void JBGFillGradientCircle(CGContextRef ctx, CGPoint center_1, CGFloat r_1, CGPoint center_2, CGFloat r_2, CGGradientRef fill_gradient, CGColorRef stroke_color) { if (fill_gradient) { CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation; CGContextDrawRadialGradient(ctx, fill_gradient, center_1, r_1, center_2, r_2, options); } if (stroke_color) { CGContextSetStrokeColorWithColor(ctx, stroke_color); CGContextAddArc(ctx, center_2.x, center_2.y, r_2, 0, M_PI * 2, false); CGContextStrokePath(ctx); } }
bool GiCanvasIos::rawLines(const GiContext* ctx, const Point2d* pxs, int count) { bool ret = m_draw->setPen(ctx) && count > 1; if (ret) { CGContextMoveToPoint(m_draw->getContext(), pxs[0].x, pxs[0].y); for (int i = 1; i < count; i++) { CGContextAddLineToPoint(m_draw->getContext(), pxs[i].x, pxs[i].y); } CGContextStrokePath(m_draw->getContext()); } return ret; }
void CanvasRenderingContext2D::stroke() { GraphicsContext* c = drawingContext(); if (!c) return; // FIXME: Do this through platform-independent GraphicsContext API. #if PLATFORM(CG) CGContextBeginPath(c->platformContext()); CGContextAddPath(c->platformContext(), state().m_path.platformPath()); if (!state().m_path.isEmpty()) { float lineWidth = state().m_lineWidth; float inset = -lineWidth / 2; CGRect boundingRect = CGRectInset(CGContextGetPathBoundingBox(c->platformContext()), inset, inset); willDraw(boundingRect); } if (state().m_strokeStyle->gradient()) { // Shading works on the entire clip region, so convert the current path to a clip. c->save(); CGContextReplacePathWithStrokedPath(c->platformContext()); CGContextClip(c->platformContext()); CGContextDrawShading(c->platformContext(), state().m_strokeStyle->gradient()->platformShading()); c->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); CGContextStrokePath(c->platformContext()); } #elif PLATFORM(QT) QPainterPath* path = state().m_path.platformPath(); QPainter* p = static_cast<QPainter*>(c->platformContext()); willDraw(path->controlPointRect()); if (state().m_strokeStyle->gradient()) { p->save(); p->setBrush(*(state().m_strokeStyle->gradient()->platformShading())); p->strokePath(*path, p->pen()); p->restore(); } else { if (state().m_strokeStyle->pattern()) applyStrokePattern(); p->strokePath(*path, p->pen()); } #endif clearPathForDashboardBackwardCompatibilityMode(); }
void MacVegaPrinterListener::DrawLine(const OpPoint& from, const OpPoint& to, UINT32 width) { if(width != 1) { CGContextSetLineWidth(m_ctx, width); } CGContextBeginPath(m_ctx); CGContextMoveToPoint(m_ctx, from.x, m_winHeight - from.y); CGContextAddLineToPoint(m_ctx, to.x, m_winHeight - to.y); CGContextStrokePath(m_ctx); if(width != 1) { CGContextSetLineWidth(m_ctx, 1); } }
bool GiCanvasIos::rawBeziers(const GiContext* ctx, const Point2d* pxs, int count) { bool ret = m_draw->setPen(ctx) && count > 1; if (ret) { CGContextMoveToPoint(m_draw->getContext(), pxs[0].x, pxs[0].y); for (int i = 1; i + 2 < count; i += 3) { CGContextAddCurveToPoint(m_draw->getContext(), pxs[i+0].x, pxs[i+0].y, pxs[i+1].x, pxs[i+1].y, pxs[i+2].x, pxs[i+2].y); } CGContextStrokePath(m_draw->getContext()); } return ret; }
static void gdk_quartz_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gboolean filled, GdkPoint *points, gint npoints) { CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE); int i; if (!context) return; if (!_gdk_quartz_gc_update_cg_context (gc, drawable, context, filled ? GDK_QUARTZ_CONTEXT_FILL : GDK_QUARTZ_CONTEXT_STROKE)) { gdk_quartz_drawable_release_context (drawable, context); return; } if (filled) { CGContextMoveToPoint (context, points[0].x, points[0].y); for (i = 1; i < npoints; i++) CGContextAddLineToPoint (context, points[i].x, points[i].y); CGContextClosePath (context); CGContextFillPath (context); } else { CGContextMoveToPoint (context, points[0].x + 0.5, points[0].y + 0.5); for (i = 1; i < npoints; i++) CGContextAddLineToPoint (context, points[i].x + 0.5, points[i].y + 0.5); CGContextClosePath (context); CGContextStrokePath (context); } gdk_quartz_drawable_release_context (drawable, context); }
static void Quartz_Polygon(int n, double *x, double *y, R_GE_gcontext *gc, NewDevDesc *dd) { int i; QuartzDesc *xd = (QuartzDesc*)dd->deviceSpecific; CGPoint *lines; CGContextSaveGState( GetContext(xd) ); CGContextBeginPath( GetContext(xd) ); /* Quartz_SetLineProperties(gc, dd); */ lines = (CGPoint *)malloc(sizeof(CGPoint)*(n+1)); if(lines == NULL) return; for (i = 0; i < n; i++) { lines[i].x = (float)x[i]; lines[i].y = (float)y[i]; } lines[n].x = (float)x[0]; lines[n].y = (float)y[0]; CGContextAddLines( GetContext(xd), &lines[0], n+1 ); Quartz_SetLineProperties(gc, dd); Quartz_SetFill( gc->fill, gc->gamma, dd); CGContextFillPath( GetContext(xd) ); CGContextAddLines( GetContext(xd), &lines[0], n+1 ); Quartz_SetStroke( gc->col, gc->gamma, dd); CGContextStrokePath( GetContext(xd) ); CGContextRestoreGState( GetContext(xd) ); }
void GraphicsContext::strokePath(const Path& path) { if (paintingDisabled()) return; CGContextRef context = platformContext(); CGContextBeginPath(context); CGContextAddPath(context, path.platformPath()); if (m_state.strokeGradient) { CGContextSaveGState(context); CGContextReplacePathWithStrokedPath(context); CGContextClip(context); CGContextConcatCTM(context, m_state.strokeGradient->gradientSpaceTransform()); m_state.strokeGradient->paint(this); CGContextRestoreGState(context); return; } if (m_state.strokePattern) applyStrokePattern(); CGContextStrokePath(context); }
static void gdk_quartz_draw_arc (GdkDrawable *drawable, GdkGC *gc, gboolean filled, gint x, gint y, gint width, gint height, gint angle1, gint angle2) { CGContextRef context = gdk_quartz_drawable_get_context (drawable, FALSE); float start_angle, end_angle; gboolean clockwise = FALSE; if (!context) return; if (!_gdk_quartz_gc_update_cg_context (gc, drawable, context, filled ? GDK_QUARTZ_CONTEXT_FILL : GDK_QUARTZ_CONTEXT_STROKE)) { gdk_quartz_drawable_release_context (drawable, context); return; } start_angle = angle1 * 2.0 * G_PI / 360.0 / 64.0; end_angle = start_angle + angle2 * 2.0 * G_PI / 360.0 / 64.0; /* angle2 is relative to angle1 and can be negative, which switches * the drawing direction */ if (angle2 < 0) clockwise = TRUE; /* below, flip the coordinate system back to its original y-diretion * so the angles passed to CGContextAddArc() are interpreted as * expected * * FIXME: the implementation below works only for perfect circles * (width == height). Any other aspect ratio either scales the * line width unevenly or scales away the path entirely for very * small line widths (esp. for line_width == 0, which is a hair * line on X11 but must be approximated with the thinnest possible * line on quartz). */ if (filled) { CGContextTranslateCTM (context, x + width / 2.0, y + height / 2.0); CGContextScaleCTM (context, 1.0, - (double)height / (double)width); CGContextMoveToPoint (context, 0, 0); CGContextAddArc (context, 0, 0, width / 2.0, start_angle, end_angle, clockwise); CGContextClosePath (context); CGContextFillPath (context); } else { CGContextTranslateCTM (context, x + width / 2.0 + 0.5, y + height / 2.0 + 0.5); CGContextScaleCTM (context, 1.0, - (double)height / (double)width); CGContextAddArc (context, 0, 0, width / 2.0, start_angle, end_angle, clockwise); CGContextStrokePath (context); } gdk_quartz_drawable_release_context (drawable, context); }
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) { if (paintingDisabled() || strokeStyle() == NoStroke || strokeThickness() <= 0.0f) return; CGContextRef context = platformContext(); CGContextSaveGState(context); CGContextBeginPath(context); CGContextSetShouldAntialias(context, false); int x = rect.x(); int y = rect.y(); float w = (float)rect.width(); float h = (float)rect.height(); float scaleFactor = h / w; float reverseScaleFactor = w / h; if (w != h) scale(FloatSize(1, scaleFactor)); float hRadius = w / 2; float vRadius = h / 2; float fa = startAngle; float falen = fa + angleSpan; float start = -fa * piFloat / 180.0f; float end = -falen * piFloat / 180.0f; CGContextAddArc(context, x + hRadius, (y + vRadius) * reverseScaleFactor, hRadius, start, end, true); if (w != h) scale(FloatSize(1, reverseScaleFactor)); float width = strokeThickness(); int patWidth = 0; switch (strokeStyle()) { case DottedStroke: patWidth = (int)(width / 2); break; case DashedStroke: patWidth = 3 * (int)(width / 2); break; default: break; } if (patWidth) { // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint // will be 50 pixels. int distance; if (hRadius == vRadius) distance = static_cast<int>((piFloat * hRadius) / 2.0f); else // We are elliptical and will have to estimate the distance distance = static_cast<int>((piFloat * sqrtf((hRadius * hRadius + vRadius * vRadius) / 2.0f)) / 2.0f); int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; float patternOffset = 0.0f; // Special case 1px dotted borders for speed. if (patWidth == 1) patternOffset = 1.0f; else { bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; patternOffset += remainder / 2.0f; } else patternOffset = patWidth / 2.0f; } else { if (remainder) patternOffset = (patWidth - remainder) / 2.0f; } } const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } CGContextStrokePath(context); CGContextRestoreGState(context); }
// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) return; if (strokeStyle() == NoStroke) return; float width = strokeThickness(); FloatPoint p1 = point1; FloatPoint p2 = point2; bool isVerticalLine = (p1.x() == p2.x()); // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. if (strokeStyle() == DottedStroke || strokeStyle() == DashedStroke) { if (isVerticalLine) { p1.move(0, width); p2.move(0, -width); } else { p1.move(width, 0); p2.move(-width, 0); } } if (((int)width) % 2) { if (isVerticalLine) { // We're a vertical line. Adjust our x. p1.move(0.5f, 0.0f); p2.move(0.5f, 0.0f); } else { // We're a horizontal line. Adjust our y. p1.move(0.0f, 0.5f); p2.move(0.0f, 0.5f); } } int patWidth = 0; switch (strokeStyle()) { case NoStroke: case SolidStroke: break; case DottedStroke: patWidth = (int)width; break; case DashedStroke: patWidth = 3 * (int)width; break; } CGContextRef context = platformContext(); if (shouldAntialias()) CGContextSetShouldAntialias(context, false); if (patWidth) { CGContextSaveGState(context); // Do a rect fill of our endpoints. This ensures we always have the // appearance of being a border. We then draw the actual dotted/dashed line. setCGFillColor(context, strokeColor(), strokeColorSpace()); // The save/restore make it safe to mutate the fill color here without setting it back to the old color. if (isVerticalLine) { CGContextFillRect(context, FloatRect(p1.x() - width / 2, p1.y() - width, width, width)); CGContextFillRect(context, FloatRect(p2.x() - width / 2, p2.y(), width, width)); } else { CGContextFillRect(context, FloatRect(p1.x() - width, p1.y() - width / 2, width, width)); CGContextFillRect(context, FloatRect(p2.x(), p2.y() - width / 2, width, width)); } // Example: 80 pixels with a width of 30 pixels. // Remainder is 20. The maximum pixels of line we could paint // will be 50 pixels. int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width; int remainder = distance % patWidth; int coverage = distance - remainder; int numSegments = coverage / patWidth; float patternOffset = 0.0f; // Special case 1px dotted borders for speed. if (patWidth == 1) patternOffset = 1.0f; else { bool evenNumberOfSegments = !(numSegments % 2); if (remainder) evenNumberOfSegments = !evenNumberOfSegments; if (evenNumberOfSegments) { if (remainder) { patternOffset += patWidth - remainder; patternOffset += remainder / 2; } else patternOffset = patWidth / 2; } else { if (remainder) patternOffset = (patWidth - remainder)/2; } } const CGFloat dottedLine[2] = { patWidth, patWidth }; CGContextSetLineDash(context, patternOffset, dottedLine, 2); } CGContextBeginPath(context); CGContextMoveToPoint(context, p1.x(), p1.y()); CGContextAddLineToPoint(context, p2.x(), p2.y()); CGContextStrokePath(context); if (patWidth) CGContextRestoreGState(context); if (shouldAntialias()) CGContextSetShouldAntialias(context, true); }
void QuartzWindow::draw_line(int x1, int y1, int x2, int y2) { CGContextBeginPath(myContext); CGContextMoveToPoint(myContext, x1, y1); CGContextAddLineToPoint(myContext, x2, y2); CGContextStrokePath(myContext); }
static void MusicBoxDrawIndicator(HIViewRef view, CGContextRef mboxctx) { if (!showIndicator) return; // Bar const double length[] = { 1.0, 1.0 }; CGContextSetLineWidth(mboxctx, mbxBarWidth); CGContextSetLineDash(mboxctx, 0, length, 2); CGContextSetLineJoin(mboxctx, kCGLineJoinMiter); CGContextBeginPath(mboxctx); double x = mbxOffsetX + mbxMarginX + mbxBarWidth / 2.0; for (int h = 0; h < 8; h++) { // Inactive CGContextSetRGBStrokeColor(mboxctx, (196.0 / 256.0), (200.0 / 256.0), (176.0 / 256.0), 1.0); CGContextMoveToPoint (mboxctx, x, mbxOffsetY + mbxMarginY); CGContextAddLineToPoint(mboxctx, x, mbxOffsetY + mbxMarginY + mbxBarHeight); CGContextMoveToPoint (mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY); CGContextAddLineToPoint(mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY + mbxBarHeight); CGContextStrokePath(mboxctx); // Max Channel *ch = &SoundData.channels[h]; ch->envx = ch->xenvx >> 4; ch-> left_vol_level = (ch->xenvx * ch->volume_left ) >> 11; ch->right_vol_level = (ch->xenvx * ch->volume_right) >> 11; short vl = ch-> left_vol_level; short vr = ch->right_vol_level; long long currentTime; if (vl <= 0) vl = 0; else if (vl > 64) vl = 64; else vl = (short) (yyscale * sqrt((double) vl)) & (~0 << 1); if (vr <= 0) vr = 0; else if (vr > 64) vr = 64; else vr = (short) (yyscale * sqrt((double) vr)) & (~0 << 1); if (vl < prevLVol[h]) vl = ((prevLVol[h] + vl) >> 1); if (vr < prevRVol[h]) vr = ((prevRVol[h] + vr) >> 1); Microseconds((UnsignedWide *) ¤tTime); // left if ((vl >= prevLMax[h]) && (vl > prevLVol[h])) { barTimeL[h] = currentTime; prevLMax[h] = vl; } else if ((prevLMax[h] > 0) && (barTimeL[h] + 1000000 > currentTime)) { CGContextSetRGBStrokeColor(mboxctx, (22.0 / 256.0), (156.0 / 256.0), (20.0 / 256.0), (double) (barTimeL[h] + 1000000 - currentTime) / 1000000.0); CGContextMoveToPoint (mboxctx, x, mbxOffsetY + mbxMarginY + (double) (prevLMax[h] - 2)); CGContextAddLineToPoint(mboxctx, x, mbxOffsetY + mbxMarginY + (double) (prevLMax[h] )); CGContextStrokePath(mboxctx); } else prevLMax[h] = 0; prevLVol[h] = vl; // right if ((vr >= prevRMax[h]) && (vr > prevRVol[h])) { barTimeR[h] = currentTime; prevRMax[h] = vr; } else if ((prevRMax[h] > 0) && (barTimeR[h] + 1000000 > currentTime)) { CGContextSetRGBStrokeColor(mboxctx, (22.0 / 256.0), (156.0 / 256.0), (20.0 / 256.0), (double) (barTimeR[h] + 1000000 - currentTime) / 1000000.0); CGContextMoveToPoint (mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY + (double) (prevRMax[h] - 2)); CGContextAddLineToPoint(mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY + (double) (prevRMax[h] )); CGContextStrokePath(mboxctx); } else prevRMax[h] = 0; prevRVol[h] = vr; // Active CGContextSetRGBStrokeColor(mboxctx, (22.0 / 256.0), (22.0 / 256.0), (20.0 / 256.0), 1.0); CGContextMoveToPoint (mboxctx, x, mbxOffsetY + mbxMarginY); CGContextAddLineToPoint(mboxctx, x, mbxOffsetY + mbxMarginY + (double) vl); CGContextStrokePath(mboxctx); CGContextMoveToPoint (mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY); CGContextAddLineToPoint(mboxctx, x + mbxRightBarX, mbxOffsetY + mbxMarginY + (double) vr); CGContextStrokePath(mboxctx); x += (mbxBarWidth + mbxBarSpace); } }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; TextDrawingModeFlags drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == TextModeFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { FloatSize offset; float blur; Color color; ColorSpace shadowColorSpace; graphicsContext->getShadow(offset, blur, color, shadowColorSpace); drawIntoBitmap = offset.width() || offset.height() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. const FontMetrics& fontMetrics = font->fontMetrics(); int lineGap = fontMetrics.lineGap(); textRect = IntRect(point.x() - (fontMetrics.ascent() + fontMetrics.descent()) / 2, point.y() - fontMetrics.ascent() - lineGap, totalWidth + fontMetrics.ascent() + fontMetrics.descent(), fontMetrics.lineSpacing()); bitmap = graphicsContext->createWindowsBitmap(textRect.size()); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == TextModeFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->syntheticBoldOffset()) { xform.eM21 = 0; xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { XFORM xform; GetWorldTransform(hdc, &xform); AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); if (drawingMode & TextModeFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & TextModeStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } CGContextRestoreGState(cgContext); CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.location()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }