#include "Painter.h" namespace Upp { void BufferPainter::BeginOp() { attr.onpath = false; attrstack.Add(attr); attr.hasclip = false; } void BufferPainter::EndOp() { if(attrstack.GetCount() == 0) { NEVER_("Painter::End: attribute stack is empty"); return; } pathattr = attr = attrstack.Top(); attrstack.Drop(); if(clip.GetCount() != attr.cliplevel || attr.mask) Finish(); clip.SetCount(attr.cliplevel); if(attr.mask) FinishMask(); if(attr.onpath) { attr.onpath = false; onpath = pick(onpathstack.Top()); onpathstack.Drop(); pathlen = pathlenstack.Pop(); } } void BufferPainter::TransformOp(const Xform2D& m) { ASSERT_(IsNull(current), "Cannot change transformation during path definition"); pathattr.mtx = attr.mtx = m * attr.mtx; pathattr.mtx_serial = attr.mtx_serial = ++mtx_serial; } void BufferPainter::OpacityOp(double o) { pathattr.opacity *= o; if(IsNull(current)) attr.opacity *= o; } void BufferPainter::LineCapOp(int linecap) { pathattr.cap = linecap; if(IsNull(current)) attr.cap = linecap; } void BufferPainter::LineJoinOp(int linejoin) { pathattr.join = linejoin; if(IsNull(current)) attr.join = linejoin; } void BufferPainter::MiterLimitOp(double l) { pathattr.miter_limit = l; if(IsNull(current)) attr.miter_limit = l; } void BufferPainter::EvenOddOp(bool evenodd) { pathattr.evenodd = evenodd; if(IsNull(current)) attr.evenodd = evenodd; } void BufferPainter::InvertOp(bool invert) { pathattr.invert = invert; if(IsNull(current)) attr.invert = invert; } Vector StringToDash(const String& dash, double& start); void BufferPainter::DashOp(const String& dash, double start) { String key; if(start) { key.Cat(1); RawCat(key, start); } else key.Cat(2); RawCat(key, dash); const DashInfo *d = dashes.FindPtr(key); if(!d) { DashInfo& h = dashes.Add(key); h.dash = StringToDash(dash, start); h.start = start; d = &h; } pathattr.dash = d; if(IsNull(current)) attr.dash = d; } void BufferPainter::DashOp(const Vector& dash, double start) { String key; RawCat(key, 0); RawCat(key, start); for(double h : dash) RawCat(key, h); const DashInfo *d = dashes.FindPtr(key); if(!d) { DashInfo& h = dashes.Add(key); h.start = start; h.dash = clone(dash); d = &h; } pathattr.dash = d; if(IsNull(current)) attr.dash = d; } void BufferPainter::ColorStop0(Attr& a, double pos, const RGBA& color) { pos = minmax(pos, 0.0, 1.0); ColorStop c; c.color = color; c.stop = pos; int i = FindLowerBound(a.color_stop, c); a.color_stop.Insert(i, c); } void BufferPainter::ColorStopOp(double pos, const RGBA& color) { ColorStop0(pathattr, pos, color); if(IsNull(current)) ColorStop0(attr, pos, color); } void BufferPainter::ClearStopsOp() { pathattr.color_stop.Clear(); if(IsNull(current)) attr.color_stop.Clear(); } void BufferPainter::Create(ImageBuffer& ib, int mode_) { ip = &ib; if(mode_ != mode || (Size)size != ib.GetSize()) { mode = mode_; rasterizer.Create(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL); cojob.Clear(); cofill.Clear(); render_cx = ib.GetWidth(); if(mode == MODE_SUBPIXEL) { render_cx *= 3; subpixel.Alloc(render_cx + 30); } else subpixel.Clear(); size = ib.GetSize(); co_subpixel.Clear(); co_span.Clear(); span.Clear(); } SyncCo(); if(!paths) paths.Alloc(BATCH_SIZE); path_info = paths; attr.mtx = Xform2D::Identity(); attr.cap = LINECAP_BUTT; attr.join = LINEJOIN_MITER; attr.miter_limit = 4; attr.evenodd = false; attr.hasclip = false; attr.cliplevel = 0; attr.opacity = 1; attr.dash = NULL; attr.mask = false; attr.invert = false; attr.mtx_serial = 0; pathattr = attr; ClearPath(); jobcount = fillcount = emptycount = 0; attrstack.Clear(); clip.Clear(); mask.Clear(); onpathstack.Clear(); pathlenstack.Clear(); onpath.Clear(); preclip_mtx_serial = -1; path_index = 0; } BufferPainter::BufferPainter(PainterTarget& t, double tolerance) : BufferPainter(dummy, MODE_ANTIALIASED) { alt = &t; alt_tolerance = tolerance; dummy.Create(1, 1); } }