git-svn-id: svn://ultimatepp.org/upp/trunk@733 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-01-06 22:20:15 +00:00
commit b5691c2c44
227 changed files with 128457 additions and 16 deletions

223
uppdev/plugin/cairo/Cairo.h Normal file
View file

@ -0,0 +1,223 @@
#ifndef _plugin_cairo_Cairo_h_
#define _plugin_cairo_Cairo_h_
#include <Core/Core.h>
#include <Draw/Draw.h>
#include "lib/cairo.h"
#include "lib/cairo-svg.h"
#include "lib/cairo-pdf.h"
#include "CairoPattern.h"
NAMESPACE_UPP
class Cairo : public NoCopy
{
private:
cairo_surface_t *_surface;
cairo_t *_context;
int _width, _height;
void DestroySurface()
{
if (_context != NULL)
{
cairo_status_t status = cairo_status(_context);
ASSERT_(status == CAIRO_STATUS_SUCCESS, cairo_status_to_string(status));
cairo_destroy(_context);
}
if (_surface != NULL)
cairo_surface_destroy(_surface);
}
public:
Cairo()
: _surface(NULL),
_context(NULL)
{
}
~Cairo()
{
DestroySurface();
}
int GetWidth() { return _width; }
int GetHeight() { return _height; }
void SetSurface(cairo_surface_t *surface, int width, int height);
void SetSurface(ImageBuffer &img);
void CreateSvgSurface(String const &filename, double widthInPoints = 595, double heightInPoints = 841); // DIN-A4 default size
void CreatePdfSurface(String const &filename, double widthInPoints = 595, double heightInPoints = 841); // DIN-A4 default size
cairo_t *GetContext()
{
return _context;
}
cairo_surface_t *GetSurface()
{
return _surface;
}
bool HasContext()
{
return _context != NULL;
}
void Clear(Color const &color)
{
SetSourceRGB(color);
Paint();
}
/*******************************************************************************************************/
/************** TODO: remove the following 2 methods!!! Replace them with a dedicated font system ******/
/*******************************************************************************************************/
void DrawText(double x, double y, char const * const text, double size, Color ink)
{
cairo_t *context = GetContext();
ASSERT(context != NULL);
cairo_set_font_size(context, size);
Save();
Translate(x, y + size);
SetSourceRGB(ink);
cairo_show_text(context, text);
NewPath();
Restore();
}
void DrawTextCenter(double x, double y, double width, char const * const text, double size, Color ink)
{
cairo_t *context = GetContext();
ASSERT(context != NULL);
cairo_set_font_size(context, size);
// measure string
cairo_text_extents_t extents;
cairo_text_extents(context, text, &extents);
double startX = x + (width / 2.0) - (extents.width / 2.0);
Save();
Translate(startX, y + size);
SetSourceRGB(ink);
cairo_show_text(context, text);
NewPath();
Restore();
}
/*
* Cairo cairo_t methods
* http://cairographics.org/manual/cairo-cairo-t.html
*/
void Save();
void Restore();
void PushGroup();
//cairo_push_group_with_content
void PopGroup();
void PopGroupToSource();
//cairo_get_group_target
void SetSourceRGB(double r, double g, double b);
void SetSourceRGB(Color const &color);
void SetSourceRGBA(double r, double g, double b, double a);
void SetSource(CairoPattern &pattern);
//cairo_set_source_surface
//cairo_get_source
void SetAntialias(cairo_antialias_t antialias);
cairo_antialias_t GetAntialias();
void SetDash(double const * dashes, int numDashes, double offset);
//cairo_get_dash_count
//cairo_get_dash
void SetFillRule(cairo_fill_rule_t fillRule);
cairo_fill_rule_t GetFillRule();
void SetLineCap(cairo_line_cap_t lineCap);
cairo_line_cap_t GetLineCap();
void SetLineJoin(cairo_line_join_t lineJoin);
cairo_line_join_t GetLineJoin();
void SetLineWidth(double width);
double GetLineWidth();
void SetMiterLimit(double limit);
double GetMiterLimit();
void SetOperator(cairo_operator_t op);
cairo_operator_t GetOperator();
void SetTolerance(double tolerance);
double GetTolerance();
void Clip(bool preserve = false);
//cairo_clip_extents
//cairo_reset_clip
//cairo_rectangle_list_destroy
//cairo_copy_clip_rectangle_list
void Fill(bool preserve = false);
//cairo_fill_extents
//cairo_in_fill
//cairo_mask
//cairo_mask_surface
void Paint(double alpha = 1.0);
void Stroke(bool preserve = false);
//cairo_stroke_extents
//cairo_in_stroke
//cairo_copy_page
//cairo_show_page
//cairo_get_reference_count probably not needed
//cairo_set_user_data probably not needed
//cairo_get_user_data probably not needed
/*
* Cairo transformation methods
* http://cairographics.org/manual/cairo-Transformations.html
*/
void Translate(double tx, double ty);
void Scale(double sx, double sy);
void Rotate(double angle);
//cairo_transform
//cairo_set_matrix
//cairo_get_matrix
void IdentityMatrix();
//cairo_user_to_device
//cairo_user_to_device_distance
//cairo_device_to_user
//cairo_device_to_user_distance
/*
* Cairo path methods
* http://cairographics.org/manual/cairo-Paths.html
*/
//cairo_copy_path
//cairo_copy_path_flat
//cairo_path_destroy
//cairo_append_path
//cairo_has_current_point
Pointf GetCurrentPoint();
void NewPath();
//cairo_new_sub_path
void ClosePath();
void Arc(double xc, double yc, double radius, double angle1, double angle2);
//cairo_arc_negative
void CurveTo(double x1, double y1, double x2, double y2, double x3, double y3);
void LineTo(double x, double y);
void MoveTo(double x, double y);
void Rectangle(double x, double y, double width, double height);
//cairo_glyph_path
//cairo_text_path
void RelCurveTo(double x1, double y1, double x2, double y2, double x3, double y3);
void RelLineTo(double x, double y);
void RelMoveTo(double x, double y);
//cairo_path_extents
};
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,264 @@
#ifndef _plugin_cairo_CairoCtrl_h_
#define _plugin_cairo_CairoCtrl_h_
#include <CtrlLib/CtrlLib.h>
#include "Cairo.h"
#include "CairoDraw.h"
NAMESPACE_UPP
#ifdef PLATFORM_WIN32
#include "lib/cairo-win32.h"
class CairoCtrl : public DHCtrl
{
private:
Drawing const *_drawing;
Color const *_backgroundColor;
HDC _hDC;
Cairo _cairo;
bool _doubleBuffering;
void DoPaint()
{
if (!_cairo.HasContext())
return;
CairoDraw draw(_cairo);
if (_drawing == NULL)
{
if (_backgroundColor != NULL)
_cairo.Clear(*_backgroundColor);
CairoPaint(_cairo);
UppPaint(draw);
}
else
{
_cairo.Clear(_backgroundColor == NULL ? White() : *_backgroundColor);
Size drawingSize = _drawing->GetSize();
Size size = GetSize();
Size drawSize = size;
int dx = 0, dy = 0;
if(drawingSize.cy * size.cx < size.cy * drawingSize.cx)
{
drawSize.cy = drawingSize.cy * size.cx / drawingSize.cx;
dy = (size.cy - drawSize.cy) / 2;
}
else
{
drawSize.cx = drawingSize.cx * size.cy / drawingSize.cy;
dx = (size.cx - drawSize.cx) / 2;
}
draw.Clipoff(dx, dy, drawSize.cx, drawSize.cy);
draw.DrawDrawing(drawSize, *_drawing);
draw.End();
}
if (_doubleBuffering)
BitBlt(_hDC, Point(0, 0), cairo_win32_surface_get_dc(_cairo.GetSurface()), GetSize());
}
protected:
// Called on paint events
virtual void CairoPaint(Cairo &cairo) { WhenCairoPaint(cairo); }
virtual void UppPaint(Draw &draw) { WhenPaint(draw); }
public:
Callback1<Cairo &> WhenCairoPaint;
Callback1<Draw &> WhenPaint;
CairoCtrl()
: _drawing(NULL),
_hDC(NULL),
_doubleBuffering(true),
_backgroundColor(NULL)
{}
~CairoCtrl()
{
if (_hDC != NULL)
ReleaseDC(GetHWND(), _hDC);
if (_backgroundColor != NULL)
delete _backgroundColor;
}
void Set(Drawing const * const drawing)
{
_drawing = drawing;
Refresh();
}
void Background(Color const &color)
{
if (_backgroundColor != NULL)
delete _backgroundColor;
_backgroundColor = new Color(color);
}
void SetDoubleBuffering(bool buffer = true)
{
_doubleBuffering = buffer;
State(LAYOUTPOS);
}
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_PAINT)
{
PAINTSTRUCT ps;
BeginPaint(GetHWND(), &ps);
DoPaint();
EndPaint(GetHWND(), &ps);
return 0;
}
else if(message == WM_ERASEBKGND)
return 1;
return DHCtrl::WindowProc(message, wParam, lParam);
}
virtual void State(int reason)
{
DHCtrl::State(reason);
if (reason == OPEN || reason == LAYOUTPOS)
{
HWND hwnd = GetHWND();
if (hwnd != NULL)
_hDC = ::GetDC(hwnd);
if (_hDC != NULL)
{
if (_doubleBuffering)
_cairo.SetSurface(cairo_win32_surface_create_with_ddb(_hDC, CAIRO_FORMAT_RGB24, GetSize().cx, GetSize().cy), GetSize().cx, GetSize().cy);
else
_cairo.SetSurface(cairo_win32_surface_create(_hDC), GetSize().cx, GetSize().cy);
}
}
else if (reason == CLOSE && _hDC != NULL)
{
ReleaseDC(GetHWND(), _hDC);
_hDC = NULL;
}
}
};
#else
class CairoCtrl : public Ctrl
{
private:
Drawing const *_drawing;
Color const *_backgroundColor;
Cairo _cairo;
ImageBuffer _buffer;
void DoPaint()
{
if (!_cairo.HasContext())
return;
CairoDraw draw(_cairo);
if (_drawing == NULL)
{
if (_backgroundColor != NULL)
_cairo.Clear(*_backgroundColor);
CairoPaint(_cairo);
UppPaint(draw);
}
else
{
_cairo.Clear(_backgroundColor == NULL ? White() : *_backgroundColor);
Size drawingSize = _drawing->GetSize();
Size size = GetSize();
Size drawSize = size;
int dx = 0, dy = 0;
if(drawingSize.cy * size.cx < size.cy * drawingSize.cx)
{
drawSize.cy = drawingSize.cy * size.cx / drawingSize.cx;
dy = (size.cy - drawSize.cy) / 2;
}
else
{
drawSize.cx = drawingSize.cx * size.cy / drawingSize.cy;
dx = (size.cx - drawSize.cx) / 2;
}
draw.Clipoff(dx, dy, drawSize.cx, drawSize.cy);
draw.DrawDrawing(drawSize, *_drawing);
draw.End();
}
}
virtual void Paint(Draw& draw)
{
if (GetSize() != _buffer.GetSize())
{
_buffer.Create(GetSize());
_cairo.SetSurface(_buffer);
}
if (_buffer.IsEmpty())
return;
DoPaint();
Image i = _buffer;
draw.DrawImage(0, 0, i);
_buffer = i;
}
protected:
// Called on paint events
virtual void CairoPaint(Cairo &cairo) { WhenCairoPaint(cairo); }
virtual void UppPaint(Draw &draw) { WhenPaint(draw); }
public:
Callback1<Cairo &> WhenCairoPaint;
Callback1<Draw &> WhenPaint;
CairoCtrl()
: _drawing(NULL),
_backgroundColor(NULL)
{}
~CairoCtrl()
{
if (_backgroundColor != NULL)
delete _backgroundColor;
}
void Set(Drawing const * const drawing)
{
_drawing = drawing;
Refresh();
}
void Background(Color const &color)
{
if (_backgroundColor != NULL)
delete _backgroundColor;
_backgroundColor = new Color(color);
}
void SetDoubleBuffering(bool buffer = true) {}
};
#endif
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,259 @@
#include "CairoDraw.h"
NAMESPACE_UPP
void CairoDraw::BeginOp()
{
_cairo.Save();
_offsetStack.Add(actual_offset);
_clipStack.Add(_actualClip);
}
void CairoDraw::EndOp()
{
_cairo.Restore();
actual_offset = _offsetStack.Pop();
_actualClip = _clipStack.Pop();
}
void CairoDraw::OffsetOp(Point p)
{
Begin();
_cairo.Translate(p.x, p.y);
actual_offset += p;
_actualClip -= p;
}
bool CairoDraw::ClipOp(const Rect& r)
{
Begin();
_cairo.Rectangle(r.left, r.top, r.Width(), r.Height());
_cairo.Clip();
_actualClip &= r;
return !_actualClip.IsEmpty();
}
bool CairoDraw::ClipoffOp(const Rect& r)
{
Begin();
_cairo.Translate(r.left, r.top);
_cairo.Rectangle(0, 0, r.Width(), r.Height());
_cairo.Clip();
actual_offset += r.TopLeft();
_actualClip &= r;
_actualClip -= r.TopLeft();
return !_actualClip.IsEmpty();
}
bool CairoDraw::ExcludeClipOp(const Rect& r)
{
_cairo.MoveTo(0, 0);
_cairo.LineTo(_cairo.GetWidth(), 0);
_cairo.LineTo(_cairo.GetWidth(), _cairo.GetHeight());
_cairo.LineTo(0, _cairo.GetHeight());
_cairo.LineTo(0, r.bottom);
_cairo.LineTo(r.right, r.bottom);
_cairo.LineTo(r.right, r.top);
_cairo.LineTo(r.left, r.top);
_cairo.LineTo(r.left, r.bottom);
_cairo.LineTo(0, r.bottom);
_cairo.ClosePath();
_cairo.Clip();
return !_actualClip.IsEmpty();
}
bool CairoDraw::IntersectClipOp(const Rect& r)
{
_cairo.Rectangle(r.left, r.top, r.Width(), r.Height());
_cairo.Clip();
_actualClip &= r;
return !_actualClip.IsEmpty();
}
Rect CairoDraw::GetClipOp() const
{
return _actualClip;
}
bool CairoDraw::IsPaintingOp(const Rect& r) const
{
return true;
}
void CairoDraw::DrawRectOp(int x, int y, int cx, int cy, Color color)
{
_cairo.Rectangle(x, y, cx, cy);
_cairo.SetSourceRGB(color);
_cairo.Fill();
}
void CairoDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
{
_cairo.Save();
cairo_t *context = _cairo.GetContext();
ASSERT(context != NULL);
cairo_surface_t *imgSurface = cairo_image_surface_create_for_data((unsigned char *)&(img[0]->b),
CAIRO_FORMAT_ARGB32,
img.GetWidth(),
img.GetHeight(),
img.GetWidth() * 4);
_cairo.Translate(x, y);
_cairo.Scale((double)cx / img.GetWidth(), (double)cy / img.GetHeight());
cairo_set_source_surface(context, imgSurface, 0, 0);
cairo_rectangle(context, 0, 0, cx, cy); //todo: src rect
_cairo.Fill();
cairo_surface_destroy(imgSurface);
_cairo.Restore();
}
void CairoDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
{
if (width == 0) width = 1;
_cairo.SetLineCap(CAIRO_LINE_CAP_ROUND);
_cairo.SetSourceRGB(color);
_cairo.SetLineWidth(width);
_cairo.MoveTo(x1 + 0.5, y1 + 0.5);
_cairo.LineTo(x2 + 0.5, y2 + 0.5);
_cairo.Stroke();
}
void CairoDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count,
const int *counts, int count_count,
int width, Color color, Color doxor)
{
if (width == 0) width = 1;
for (int i = 0; i < count_count; i++)
{
ASSERT(counts[i] >= 1);
_cairo.MoveTo(vertices->x + 0.5, vertices->y + 0.5);
vertices++;
for (int j = 1; j < counts[i]; j++, vertices++)
_cairo.LineTo(vertices->x + 0.5, vertices->y + 0.5);
}
_cairo.SetLineCap(CAIRO_LINE_CAP_ROUND);
_cairo.SetLineJoin(CAIRO_LINE_JOIN_ROUND);
_cairo.SetLineWidth(width);
_cairo.SetSourceRGB(color);
_cairo.Stroke();
}
void CairoDraw::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
const int *subpolygon_counts, int scc,
const int *disjunct_polygon_counts, int dpcc,
Color color, int width, Color outline,
uint64 pattern, Color doxor)
{
if (width == 0) width = 1;
for (int i = 0; i < scc; i++)
{
ASSERT(subpolygon_counts[i] >= 1);
_cairo.MoveTo(vertices->x, vertices->y);
vertices++;
for (int j = 1; j < subpolygon_counts[i]; j++, vertices++)
_cairo.LineTo(vertices->x, vertices->y);
_cairo.ClosePath();
}
_cairo.SetSourceRGB(color);
_cairo.Fill(true);
_cairo.SetLineCap(CAIRO_LINE_CAP_ROUND);
_cairo.SetLineJoin(CAIRO_LINE_JOIN_ROUND);
_cairo.SetLineWidth(width);
_cairo.SetSourceRGB(outline);
_cairo.Stroke();
}
void CairoDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor)
{
if (pen == 0) pen = 1;
_cairo.Save();
_cairo.Translate(r.left + (r.Width() / 2.0), r.top + (r.Height() / 2.0));
_cairo.Scale(r.Width() / 2.0, r.Height() / 2.0);
_cairo.Arc(0.0, 0.0, 1.0, 0.0, 2 * M_PI);
_cairo.Restore();
_cairo.SetSourceRGB(color);
_cairo.Fill(pen != (int)Null);
if (pen != (int)Null)
{
_cairo.SetLineWidth(pen);
_cairo.SetSourceRGB(pencolor);
_cairo.Stroke();
}
}
void CairoDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
{
if (width == 0) width = 1;
//TODO
}
void CairoDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
cairo_t *context = _cairo.GetContext();
ASSERT(context != NULL);
/*HFONT hFont = CreateFont(font.GetHeight() ? -abs(font.GetHeight()) : -12,
font.GetWidth(), angle, angle, font.IsBold() ? FW_BOLD : FW_NORMAL,
font.IsItalic(), font.IsUnderline(), font.IsStrikeout(),
Font::GetFaceInfo(font.GetFace()) & Font::SYMBOLTYPE ? SYMBOL_CHARSET : DEFAULT_CHARSET,
font.IsTrueTypeOnly() ? OUT_TT_ONLY_PRECIS : OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
font.IsNonAntiAliased() ? NONANTIALIASED_QUALITY
: DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
Font::GetFaceName(font.GetFace())/*sFontFace().GetKey(font.GetFace())* /);
cairo_font_face_t *fontFace = cairo_win32_font_face_create_for_hfont(hFont);
cairo_set_font_face(context, fontFace);*/
cairo_set_font_size(context, font.GetHeight());
_cairo.Save();
_cairo.Translate(x, y + (font.GetHeight() ? abs(font.GetHeight()) : 12));
_cairo.Rotate(angle * (-3.14159 / 1800.0));
_cairo.SetSourceRGB(ink);
WString tempWString = text;
cairo_show_text(context, tempWString.ToString());
_cairo.NewPath();
_cairo.Restore();
/*cairo_font_face_destroy(fontFace);*/
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,51 @@
#ifndef _plugin_cairo_CairoDraw_h_
#define _plugin_cairo_CairoDraw_h_
#include <Draw/Draw.h>
#include "Cairo.h"
NAMESPACE_UPP
class CairoDraw : public Draw
{
private:
Vector<Point> _offsetStack;
Vector<Rect> _clipStack;
Rect _actualClip;
Cairo &_cairo;
public:
CairoDraw(Cairo &cairo)
: _cairo(cairo)
{}
virtual void BeginOp();
virtual void EndOp();
virtual void OffsetOp(Point p);
virtual bool ClipOp(const Rect& r);
virtual bool ClipoffOp(const Rect& r);
virtual bool ExcludeClipOp(const Rect& r);
virtual bool IntersectClipOp(const Rect& r);
virtual Rect GetClipOp() const;
virtual bool IsPaintingOp(const Rect& r) const;
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count,
const int *counts, int count_count,
int width, Color color, Color doxor);
virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count,
const int *subpolygon_counts, int scc,
const int *disjunct_polygon_counts, int dpcc,
Color color, int width, Color outline,
uint64 pattern, Color doxor);
virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor);
virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color);
virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx);
};
END_UPP_NAMESPACE
#endif

View file

@ -0,0 +1,185 @@
#ifndef _plugin_cairo_CairoPattern_h_
#define _plugin_cairo_CairoPattern_h_
#include <Core/Core.h>
#include "lib/cairo.h"
NAMESPACE_UPP
#if 1
#define CAIRO_METHOD_ENTER() ASSERT(_pattern != NULL)
#define CAIRO_METHOD_LEAVE() { \
cairo_status_t status = cairo_pattern_status(_pattern); \
ASSERT_(status == CAIRO_STATUS_SUCCESS, cairo_status_to_string(status)); \
}
#else
#define CAIRO_METHOD_ENTER()
#define CAIRO_METHOD_LEAVE()
#endif
class CairoPattern : public NoCopy /*abstract*/
{
protected:
cairo_pattern_t *_pattern;
CairoPattern()
: _pattern(NULL)
{}
virtual ~CairoPattern()
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
}
public:
cairo_pattern_t *GetPattern()
{
return _pattern;
}
void SetExtend(cairo_extend_t extend)
{
CAIRO_METHOD_ENTER();
cairo_pattern_set_extend(_pattern, extend);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_extend ()
void SetFilter(cairo_filter_t filter)
{
CAIRO_METHOD_ENTER();
cairo_pattern_set_filter(_pattern, filter);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_filter ()
//cairo_pattern_set_matrix ()
//cairo_pattern_get_matrix ()
//cairo_pattern_get_type ()
};
class CairoGradient : public CairoPattern /*abstract*/
{
protected:
CairoGradient() {}
public:
void AddColorStopRGB(double offset, double r, double g, double b)
{
CAIRO_METHOD_ENTER();
cairo_pattern_add_color_stop_rgb(_pattern, offset, r, g, b);
CAIRO_METHOD_LEAVE();
}
void AddColorStopRGB(double offset, Color const &color)
{
AddColorStopRGB(offset, color.GetR() / 255.0, color.GetG() / 255.0, color.GetB() / 255.0);
}
void AddColorStopRGBA(double offset, double r, double g, double b, double a)
{
CAIRO_METHOD_ENTER();
cairo_pattern_add_color_stop_rgba(_pattern, offset, r, g, b, a);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_color_stop_count ()
//cairo_pattern_get_color_stop_rgba ()
};
class CairoSolidPattern : public CairoPattern
{
public:
CairoSolidPattern(double r, double g, double b) { SetRGB(r, g, b); }
CairoSolidPattern(Color const &color) { SetRGB(color); }
CairoSolidPattern(double r, double g, double b, double a) { SetRGBA(r, g, b, a); }
void SetRGB(double r, double g, double b)
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
_pattern = cairo_pattern_create_rgb(r, g, b);
CAIRO_METHOD_LEAVE();
}
void SetRGB(Color const &color)
{
SetRGB(color.GetR() / 255.0, color.GetG() / 255.0, color.GetB() / 255.0);
}
void SetRGBA(double r, double g, double b, double a)
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
_pattern = cairo_pattern_create_rgba(r, g, b, a);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_rgba ()
};
class CairoLinearGradient : public CairoGradient
{
public:
CairoLinearGradient(double x0, double y0, double x1, double y1) { Set(x0, y0, x1, y1); }
void Set(double x0, double y0, double x1, double y1)
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
_pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_linear_points ()
};
class CairoRadialGradient : public CairoGradient
{
public:
CairoRadialGradient(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1)
{
Set(cx0, cy0, radius0, cx1, cy1, radius1);
}
void Set(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1)
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
_pattern = cairo_pattern_create_radial(cx0, cy0, radius0, cx1, cy1, radius1);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_radial_circles ()
};
class CairoSurfacePattern : public CairoPattern
{
public:
CairoSurfacePattern(cairo_surface_t *surface) { Set(surface); }
void Set(cairo_surface_t *surface)
{
if (_pattern != NULL)
cairo_pattern_destroy(_pattern);
_pattern = cairo_pattern_create_for_surface(surface);
CAIRO_METHOD_LEAVE();
}
//cairo_pattern_get_surface ()
};
END_UPP_NAMESPACE
#undef CAIRO_METHOD_ENTER
#undef CAIRO_METHOD_LEAVE
#endif

View file

@ -0,0 +1,390 @@
#include "Cairo.h"
#include "CairoPattern.h"
NAMESPACE_UPP
void Cairo::SetSurface(cairo_surface_t *surface, int width, int height)
{
ASSERT(surface != NULL);
DestroySurface();
_surface = surface;
_context = cairo_create(_surface);
_width = width;
_height = height;
}
void Cairo::SetSurface(ImageBuffer &img)
{
ASSERT(img.IsEmpty() == false);
cairo_surface_t *surface = cairo_image_surface_create_for_data((unsigned char *)&(img[0]->b),
CAIRO_FORMAT_ARGB32,
img.GetSize().cx,
img.GetSize().cy,
img.GetSize().cx * 4);
SetSurface(surface, img.GetSize().cx, img.GetSize().cy);
}
void Cairo::CreateSvgSurface(String const &filename, double widthInPoints, double heightInPoints)
{
SetSurface(cairo_svg_surface_create(filename, widthInPoints, heightInPoints), static_cast<int>(widthInPoints), static_cast<int>(heightInPoints));
}
void Cairo::CreatePdfSurface(String const &filename, double widthInPoints, double heightInPoints)
{
SetSurface(cairo_pdf_surface_create(filename, widthInPoints, heightInPoints), static_cast<int>(widthInPoints), static_cast<int>(heightInPoints));
}
#if 1
#define CAIRO_METHOD_ENTER() ASSERT(_context != NULL)
#define CAIRO_METHOD_LEAVE() { \
cairo_status_t status = cairo_status(_context); \
ASSERT_(status == CAIRO_STATUS_SUCCESS, cairo_status_to_string(status)); \
}
#else
#define CAIRO_METHOD_ENTER()
#define CAIRO_METHOD_LEAVE()
#endif
void Cairo::Save()
{
CAIRO_METHOD_ENTER();
cairo_save(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::Restore()
{
CAIRO_METHOD_ENTER();
cairo_restore(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::PushGroup()
{
CAIRO_METHOD_ENTER();
cairo_push_group(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::PopGroup()
{
CAIRO_METHOD_ENTER();
cairo_pop_group(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::PopGroupToSource()
{
CAIRO_METHOD_ENTER();
cairo_pop_group_to_source(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::SetSourceRGB(double r, double g, double b)
{
CAIRO_METHOD_ENTER();
cairo_set_source_rgb(_context, r, g, b);
CAIRO_METHOD_LEAVE();
}
void Cairo::SetSourceRGB(Color const &color)
{
CAIRO_METHOD_ENTER();
cairo_set_source_rgb(_context, color.GetR() / 255.0, color.GetG() / 255.0, color.GetB() / 255.0);
CAIRO_METHOD_LEAVE();
}
void Cairo::SetSourceRGBA(double r, double g, double b, double a)
{
CAIRO_METHOD_ENTER();
cairo_set_source_rgba(_context, r, g, b, a);
CAIRO_METHOD_LEAVE();
}
void Cairo::SetSource(CairoPattern &pattern)
{
CAIRO_METHOD_ENTER();
cairo_set_source(_context, pattern.GetPattern());
CAIRO_METHOD_LEAVE();
}
void Cairo::SetAntialias(cairo_antialias_t antialias)
{
CAIRO_METHOD_ENTER();
cairo_set_antialias(_context, antialias);
CAIRO_METHOD_LEAVE();
}
cairo_antialias_t Cairo::GetAntialias()
{
CAIRO_METHOD_ENTER();
cairo_antialias_t result = cairo_get_antialias(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetDash(double const * dashes, int numDashes, double offset)
{
CAIRO_METHOD_ENTER();
cairo_set_dash(_context, dashes, numDashes, offset);
CAIRO_METHOD_LEAVE();
}
void Cairo::SetFillRule(cairo_fill_rule_t fillRule)
{
CAIRO_METHOD_ENTER();
cairo_set_fill_rule(_context, fillRule);
CAIRO_METHOD_LEAVE();
}
cairo_fill_rule_t Cairo::GetFillRule()
{
CAIRO_METHOD_ENTER();
cairo_fill_rule_t result = cairo_get_fill_rule(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetLineCap(cairo_line_cap_t lineCap)
{
CAIRO_METHOD_ENTER();
cairo_set_line_cap(_context, lineCap);
CAIRO_METHOD_LEAVE();
}
cairo_line_cap_t Cairo::GetLineCap()
{
CAIRO_METHOD_ENTER();
cairo_line_cap_t result = cairo_get_line_cap(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetLineJoin(cairo_line_join_t lineJoin)
{
CAIRO_METHOD_ENTER();
cairo_set_line_join(_context, lineJoin);
CAIRO_METHOD_LEAVE();
}
cairo_line_join_t Cairo::GetLineJoin()
{
CAIRO_METHOD_ENTER();
cairo_line_join_t result = cairo_get_line_join(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetLineWidth(double width)
{
CAIRO_METHOD_ENTER();
cairo_set_line_width(_context, width);
CAIRO_METHOD_LEAVE();
}
double Cairo::GetLineWidth()
{
CAIRO_METHOD_ENTER();
double result = cairo_get_line_width(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetMiterLimit(double limit)
{
CAIRO_METHOD_ENTER();
cairo_set_miter_limit(_context, limit);
CAIRO_METHOD_LEAVE();
}
double Cairo::GetMiterLimit()
{
CAIRO_METHOD_ENTER();
double result = cairo_get_miter_limit(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetOperator(cairo_operator_t op)
{
CAIRO_METHOD_ENTER();
cairo_set_operator(_context, op);
CAIRO_METHOD_LEAVE();
}
cairo_operator_t Cairo::GetOperator()
{
CAIRO_METHOD_ENTER();
cairo_operator_t result = cairo_get_operator(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::SetTolerance(double tolerance)
{
CAIRO_METHOD_ENTER();
cairo_set_tolerance(_context, tolerance);
CAIRO_METHOD_LEAVE();
}
double Cairo::GetTolerance()
{
CAIRO_METHOD_ENTER();
double result = cairo_get_tolerance(_context);
CAIRO_METHOD_LEAVE();
return result;
}
void Cairo::Clip(bool preserve)
{
CAIRO_METHOD_ENTER();
if (!preserve)
cairo_clip(_context);
else
cairo_clip_preserve(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::Fill(bool preserve)
{
CAIRO_METHOD_ENTER();
if (!preserve)
cairo_fill(_context);
else
cairo_fill_preserve(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::Paint(double alpha)
{
CAIRO_METHOD_ENTER();
if (alpha >= 1.0)
cairo_paint(_context);
else
cairo_paint_with_alpha(_context, alpha);
CAIRO_METHOD_LEAVE();
}
void Cairo::Stroke(bool preserve)
{
CAIRO_METHOD_ENTER();
if (!preserve)
cairo_stroke(_context);
else
cairo_stroke_preserve(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::Translate(double tx, double ty)
{
CAIRO_METHOD_ENTER();
cairo_translate(_context, tx, ty);
CAIRO_METHOD_LEAVE();
}
void Cairo::Scale(double sx, double sy)
{
CAIRO_METHOD_ENTER();
cairo_scale(_context, sx, sy);
CAIRO_METHOD_LEAVE();
}
void Cairo::Rotate(double angle)
{
CAIRO_METHOD_ENTER();
cairo_rotate(_context, angle);
CAIRO_METHOD_LEAVE();
}
void Cairo::IdentityMatrix()
{
CAIRO_METHOD_ENTER();
cairo_identity_matrix(_context);
CAIRO_METHOD_LEAVE();
}
Pointf Cairo::GetCurrentPoint()
{
Pointf p;
CAIRO_METHOD_ENTER();
cairo_get_current_point(_context, &p.x, &p.y);
CAIRO_METHOD_LEAVE();
return p;
}
void Cairo::NewPath()
{
CAIRO_METHOD_ENTER();
cairo_new_path(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::ClosePath()
{
CAIRO_METHOD_ENTER();
cairo_close_path(_context);
CAIRO_METHOD_LEAVE();
}
void Cairo::Arc(double xc, double yc, double radius, double angle1, double angle2)
{
CAIRO_METHOD_ENTER();
cairo_arc(_context, xc, yc, radius, angle1, angle2);
CAIRO_METHOD_LEAVE();
}
void Cairo::CurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
{
CAIRO_METHOD_ENTER();
cairo_curve_to(_context, x1, y1, x2, y2, x3, y3);
CAIRO_METHOD_LEAVE();
}
void Cairo::LineTo(double x, double y)
{
CAIRO_METHOD_ENTER();
cairo_line_to(_context, x, y);
CAIRO_METHOD_LEAVE();
}
void Cairo::MoveTo(double x, double y)
{
CAIRO_METHOD_ENTER();
cairo_move_to(_context, x, y);
CAIRO_METHOD_LEAVE();
}
void Cairo::Rectangle(double x, double y, double width, double height)
{
CAIRO_METHOD_ENTER();
cairo_rectangle(_context, x, y, width, height);
CAIRO_METHOD_LEAVE();
}
void Cairo::RelCurveTo(double x1, double y1, double x2, double y2, double x3, double y3)
{
CAIRO_METHOD_ENTER();
cairo_rel_curve_to(_context, x1, y1, x2, y2, x3, y3);
CAIRO_METHOD_LEAVE();
}
void Cairo::RelLineTo(double x, double y)
{
CAIRO_METHOD_ENTER();
cairo_rel_line_to(_context, x, y);
CAIRO_METHOD_LEAVE();
}
void Cairo::RelMoveTo(double x, double y)
{
CAIRO_METHOD_ENTER();
cairo_rel_move_to(_context, x, y);
CAIRO_METHOD_LEAVE();
}
END_UPP_NAMESPACE

View file

@ -0,0 +1,8 @@
#ifndef CAIRO_VERSION_H
#define CAIRO_VERSION_H
#define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 8
#define CAIRO_VERSION_MICRO 0
#endif

View file

@ -0,0 +1,27 @@
uses
Core,
plugin\png,
plugin\pixman;
library(WIN32) "user32 gdi32 msimg32";
library(!WIN32) cairo;
options(WIN32) "-I\"./lib\" -I\"../pixman/lib\"";
options(WIN32) "-I\"C:/upp/uppsrc/plugin/z/lib\" -I\"C:/upp/uppsrc/plugin/png/lib\"";
options(WIN32) -D_CRT_SECURE_NO_WARNINGS;
file
Cairo.h,
CairoUpp.cpp,
CairoPattern.h,
CairoDraw.h,
CairoDraw.cpp,
CairoCtrl.h,
cairolib.c,
cairolibwin32.c,
Cairo readonly separator,
lib/cairo-features.h;

View file

@ -0,0 +1,92 @@
#ifdef flagWIN32
#undef CAIRO_VERSION_H
#undef CAIRO_VERSION_MAJOR
#undef CAIRO_VERSION_MINOR
#undef CAIRO_VERSION_MICRO
#include "lib/cairo-version.c"
#include "lib/cairo-analysis-surface.c"
#include "lib/cairo-arc.c"
#include "lib/cairo-array.c"
#include "lib/cairo-atomic.c"
#include "lib/cairo-base85-stream.c"
#include "lib/cairo-bentley-ottmann.c"
#include "lib/cairo-cache.c"
#undef _BSD_SOURCE
#include "lib/cairo-cff-subset.c"
#include "lib/cairo-clip.c"
#include "lib/cairo-color.c"
//#include "lib/cairo-debug.c"
#include "lib/cairo-deflate-stream.c"
#include "lib/cairo-fixed.c"
#undef _BSD_SOURCE
#include "lib/cairo-font-face.c"
#include "lib/cairo-font-face-twin.c"
#include "lib/cairo-font-face-twin-data.c"
#include "lib/cairo-font-options.c"
#include "lib/cairo-freelist.c"
#include "lib/cairo-gstate.c"
#include "lib/cairo-hash.c"
#include "lib/cairo-hull.c"
#include "lib/cairo-image-surface.c"
#include "lib/cairo-lzw.c"
#include "lib/cairo-matrix.c"
#include "lib/cairo-meta-surface.c"
#include "lib/cairo-misc.c"
#include "lib/cairo-mutex.c"
#undef _BSD_SOURCE
#include "lib/cairo-output-stream.c"
#include "lib/cairo-paginated-surface.c"
#include "lib/cairo-path-bounds.c"
#include "lib/cairo-path-fill.c"
#include "lib/cairo-path-fixed.c"
#include "lib/cairo-path-stroke.c"
#include "lib/cairo-path.c"
#include "lib/cairo-pattern.c"
#include "lib/cairo-pdf-operators.c"
#undef _BSD_SOURCE
#include "lib/cairo-pdf-surface.c"
#include "lib/cairo-pen.c"
#include "lib/cairo-polygon.c"
#include "lib/cairo-png.c"
#include "lib/cairo-rectangle.c"
#include "lib/cairo-region.c"
#include "lib/cairo-scaled-font-subsets.c"
#include "lib/cairo-scaled-font.c"
#include "lib/cairo-skiplist.c"
#include "lib/cairo-slope.c"
#include "lib/cairo-spline.c"
#include "lib/cairo-stroke-style.c"
#include "lib/cairo-surface-fallback.c"
#include "lib/cairo-surface.c"
#include "lib/cairo-svg-surface.c"
#include "lib/cairo-traps.c"
#include "lib/cairo-truetype-subset.c"
#include "lib/cairo-type1-fallback.c"
#include "lib/cairo-type3-glyph-surface.c"
#include "lib/cairo-unicode.c"
#include "lib/cairo-user-font.c"
#include "lib/cairo-wideint.c"
#include "lib/cairo.c"
// files that would be needed if you want to compile for linux.
// currently we just use the cairo library from the system
/*
#include "lib/cairo-ft-font.c"
#include "lib/cairo-xlib-screen.c"
#include "lib/cairo-xlib-surface.c"
#include "lib/cairo-xlib-visual.c"
#include "lib/cairo-type1-subset.c"
#include "lib/cairo-xlib-display.c"
*/
#endif

View file

@ -0,0 +1,8 @@
#ifdef flagWIN32
//#include "lib/cairo-win32.c"
#include "lib/cairo-win32-font.c"
#include "lib/cairo-win32-printing-surface.c"
#include "lib/cairo-win32-surface.c"
#endif

6
uppdev/plugin/cairo/init Normal file
View file

@ -0,0 +1,6 @@
#ifndef _plugin_cairo_icpp_init_stub
#define _plugin_cairo_icpp_init_stub
#include "Core/init"
#include "plugin\png/init"
#include "plugin\pixman/init"
#endif

View file

@ -0,0 +1,76 @@
/*
* Copyright © 2005 Keith Packard
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
*/
#ifndef CAIRO_ANALYSIS_SURFACE_H
#define CAIRO_ANALYSIS_SURFACE_H
#include "cairoint.h"
cairo_private cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *surface);
cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View file

@ -0,0 +1,988 @@
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#include "cairo-analysis-surface-private.h"
#include "cairo-paginated-private.h"
#include "cairo-region-private.h"
#include "cairo-meta-surface-private.h"
typedef struct {
cairo_surface_t base;
int width;
int height;
cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported;
cairo_bool_t has_unsupported;
cairo_region_t supported_region;
cairo_region_t fallback_region;
cairo_rectangle_int_t current_clip;
cairo_box_t page_bbox;
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
} cairo_analysis_surface_t;
cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b)
{
/* fatal errors should be checked and propagated at source */
assert (! _cairo_status_is_error (status_a));
assert (! _cairo_status_is_error (status_b));
/* return the most important status */
if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
status_b == CAIRO_INT_STATUS_UNSUPPORTED)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (status_a == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN ||
status_b == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
/* at this point we have checked all the valid internal codes, so... */
assert (status_a == CAIRO_STATUS_SUCCESS &&
status_b == CAIRO_STATUS_SUCCESS);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_analyze_meta_surface_pattern (cairo_analysis_surface_t *surface,
cairo_pattern_t *pattern)
{
cairo_surface_t *analysis = &surface->base;
cairo_surface_pattern_t *surface_pattern;
cairo_status_t status;
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_rectangle_int_t old_clip;
cairo_rectangle_int_t meta_extents;
int old_width;
int old_height;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_meta (surface_pattern->surface));
old_width = surface->width;
old_height = surface->height;
old_clip = surface->current_clip;
status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
surface->width = meta_extents.width;
surface->height = meta_extents.height;
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
p2d = pattern->matrix;
status = cairo_matrix_invert (&p2d);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
analysis);
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
surface->current_clip = old_clip;
surface->width = old_width;
surface->height = old_height;
return status;
}
static cairo_int_status_t
_add_operation (cairo_analysis_surface_t *surface,
cairo_rectangle_int_t *rect,
cairo_int_status_t backend_status)
{
cairo_int_status_t status;
cairo_box_t bbox;
if (rect->width == 0 || rect->height == 0) {
/* Even though the operation is not visible we must be careful
* to not allow unsupported operations to be replayed to the
* backend during CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
* CAIRO_PAGINATED_MODE_RENDER */
if (backend_status == CAIRO_STATUS_SUCCESS ||
backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
{
return CAIRO_STATUS_SUCCESS;
}
else
{
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
}
_cairo_box_round_to_rectangle (&bbox, rect);
}
if (surface->first_op) {
surface->first_op = FALSE;
surface->page_bbox = bbox;
} else {
if (bbox.p1.x < surface->page_bbox.p1.x)
surface->page_bbox.p1.x = bbox.p1.x;
if (bbox.p1.y < surface->page_bbox.p1.y)
surface->page_bbox.p1.y = bbox.p1.y;
if (bbox.p2.x > surface->page_bbox.p2.x)
surface->page_bbox.p2.x = bbox.p2.x;
if (bbox.p2.y > surface->page_bbox.p2.y)
surface->page_bbox.p2.y = bbox.p2.y;
}
/* If the operation is completely enclosed within the fallback
* region there is no benefit in emitting a native operation as
* the fallback image will be painted on top.
*/
if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
* that the backend only supports this operation if the
* transparency removed. If the extents of this operation does
* not intersect any other native operation, the operation is
* natively supported and the backend will blend the
* transparency into the white background.
*/
if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_STATUS_SUCCESS) {
/* Add the operation to the supported region. Operations in
* this region will be emitted as native operations.
*/
surface->has_supported = TRUE;
status = _cairo_region_union_rect (&surface->supported_region,
&surface->supported_region,
rect);
return status;
}
/* Add the operation to the unsupported region. This region will
* be painted as an image after all native operations have been
* emitted.
*/
surface->has_unsupported = TRUE;
status = _cairo_region_union_rect (&surface->fallback_region,
&surface->fallback_region,
rect);
/* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
* unsupported operations to the meta surface as using
* CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
* invoke the cairo-surface-fallback path then return
* CAIRO_STATUS_SUCCESS.
*/
if (status == CAIRO_STATUS_SUCCESS)
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
else
return status;
}
static cairo_status_t
_cairo_analysis_surface_finish (void *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
_cairo_region_fini (&surface->supported_region);
_cairo_region_fini (&surface->fallback_region);
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
double x1, y1, x2, y2;
cairo_rectangle_int_t extent;
cairo_bool_t is_empty;
if (path == NULL) {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
cairo_status_t status;
status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
if (status)
return status;
extent.x = floor (x1);
extent.y = floor (y1);
extent.width = ceil (x2) - extent.x;
extent.height = ceil (y2) - extent.y;
is_empty = _cairo_rectangle_intersect (&surface->current_clip, &extent);
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_analysis_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_analysis_surface_t *surface = abstract_surface;
return _cairo_surface_get_extents (surface->target, rectangle);
}
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->paint)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->paint) (surface->target, op,
source);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
status = _add_operation (surface, &extents, backend_status);
return status;
}
static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->mask)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->mask) (surface->target, op,
source, mask);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
backend_source_status =
_analyze_meta_surface_pattern (surface, source);
if (_cairo_status_is_error (backend_source_status))
return backend_source_status;
}
}
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
backend_mask_status =
_analyze_meta_surface_pattern (surface, mask);
if (_cairo_status_is_error (backend_mask_status))
return backend_mask_status;
}
}
backend_status =
_cairo_analysis_surface_merge_status (backend_source_status,
backend_mask_status);
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
if (_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_int_t mask_extents;
status = _cairo_pattern_get_extents (mask, &mask_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
status = _add_operation (surface, &extents, backend_status);
return status;
}
static cairo_int_status_t
_cairo_analysis_surface_stroke (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_traps_t traps;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->stroke)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->stroke) (surface->target, op,
source, path, style,
ctm, ctm_inverse,
tolerance, antialias);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_box_t box;
_cairo_box_from_rectangle (&box, &extents);
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &box);
status = _cairo_path_fixed_stroke_to_traps (path,
style,
ctm, ctm_inverse,
tolerance,
&traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_traps_extents (&traps, &box);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&box, &extents);
}
status = _add_operation (surface, &extents, backend_status);
return status;
}
static cairo_int_status_t
_cairo_analysis_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_traps_t traps;
cairo_rectangle_int_t extents;
cairo_bool_t is_empty;
if (!surface->target->backend->fill)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
tolerance, antialias);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
cairo_box_t box;
_cairo_box_from_rectangle (&box, &extents);
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &box);
status = _cairo_path_fixed_fill_to_traps (path,
fill_rule,
tolerance,
&traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_traps_extents (&traps, &box);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&box, &extents);
}
status = _add_operation (surface, &extents, backend_status);
return status;
}
static cairo_int_status_t
_cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
cairo_bool_t is_empty;
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs)
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
remaining_glyphs);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font);
else
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
status = _add_operation (surface, &extents, backend_status);
return status;
}
static cairo_bool_t
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_analysis_surface_t *surface = abstract_surface;
return cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
cairo_bool_t is_empty;
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
scaled_font);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
if (status)
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
status = _add_operation (surface, &extents, backend_status);
return status;
}
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
NULL, /* create_similar */
_cairo_analysis_surface_finish,
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
_cairo_analysis_surface_intersect_clip_path,
_cairo_analysis_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_analysis_surface_paint,
_cairo_analysis_surface_mask,
_cairo_analysis_surface_stroke,
_cairo_analysis_surface_fill,
_cairo_analysis_surface_show_glyphs,
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
cairo_surface_t *
_cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
status = target->status;
if (status)
return _cairo_surface_create_in_error (status);
surface = malloc (sizeof (cairo_analysis_surface_t));
if (surface == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
/* I believe the content type here is truly arbitrary. I'm quite
* sure nothing will ever use this value. */
_cairo_surface_init (&surface->base, &cairo_analysis_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
surface->width = width;
surface->height = height;
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
surface->target = cairo_surface_reference (target);
surface->first_op = TRUE;
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
surface->page_bbox.p1.x = 0;
surface->page_bbox.p1.y = 0;
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
if (width == -1 && height == -1) {
surface->current_clip.x = CAIRO_RECT_INT_MIN;
surface->current_clip.y = CAIRO_RECT_INT_MIN;
surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
}
return &surface->base;
}
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface;
if (abstract_surface->status)
return;
surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
}
void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*ctm = surface->ctm;
}
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return &surface->supported_region;
}
cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return &surface->fallback_region;
}
cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->has_supported;
}
cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
return surface->has_unsupported;
}
void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
cairo_box_t *bbox)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*bbox = surface->page_bbox;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
_return_success (void)
{
return CAIRO_STATUS_SUCCESS;
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* create_similar */
NULL, /* finish */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface, &cairo_null_surface_backend, content);
return surface;
}

View file

@ -0,0 +1,57 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_ARC_PRIVATE_H
#define CAIRO_ARC_PRIVATE_H
#include "cairoint.h"
cairo_private void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
cairo_private void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2);
#endif /* CAIRO_ARC_PRIVATE_H */

View file

@ -0,0 +1,292 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-arc-private.h"
/* Spline deviation from the circle in radius would be given by:
error = sqrt (x**2 + y**2) - 1
A simpler error function to work with is:
e = x**2 + y**2 - 1
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
and
abs (error) =~ 1/2 * e
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static double
_arc_error_normalized (double angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
static double
_arc_max_angle_for_tolerance_normalized (double tolerance)
{
double angle, error;
int i;
/* Use table lookup to reduce search time in most cases. */
struct {
double angle;
double error;
} table[] = {
{ M_PI / 1.0, 0.0185185185185185036127 },
{ M_PI / 2.0, 0.000272567143730179811158 },
{ M_PI / 3.0, 2.38647043651461047433e-05 },
{ M_PI / 4.0, 4.2455377443222443279e-06 },
{ M_PI / 5.0, 1.11281001494389081528e-06 },
{ M_PI / 6.0, 3.72662000942734705475e-07 },
{ M_PI / 7.0, 1.47783685574284411325e-07 },
{ M_PI / 8.0, 6.63240432022601149057e-08 },
{ M_PI / 9.0, 3.2715520137536980553e-08 },
{ M_PI / 10.0, 1.73863223499021216974e-08 },
{ M_PI / 11.0, 9.81410988043554039085e-09 },
};
int table_size = ARRAY_LENGTH (table);
for (i = 0; i < table_size; i++)
if (table[i].error < tolerance)
return table[i].angle;
++i;
do {
angle = M_PI / i++;
error = _arc_error_normalized (angle);
} while (error > tolerance);
return angle;
}
static int
_arc_segments_needed (double angle,
double radius,
cairo_matrix_t *ctm,
double tolerance)
{
double major_axis, max_angle;
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius);
max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis);
return (int) ceil (angle / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
for some value of h.
"Approximation of circular arcs by cubic poynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
From that paper, a very practical value of h is:
h = 4/3 * tan(angle/4)
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static void
_cairo_arc_segment (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_A,
double angle_B)
{
double r_sin_A, r_cos_A;
double r_sin_B, r_cos_B;
double h;
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
cairo_curve_to (cr,
xc + r_cos_A - h * r_sin_A,
yc + r_sin_A + h * r_cos_A,
xc + r_cos_B + h * r_sin_B,
yc + r_sin_B - h * r_cos_B,
xc + r_cos_B,
yc + r_sin_B);
}
static void
_cairo_arc_in_direction (cairo_t *cr,
double xc,
double yc,
double radius,
double angle_min,
double angle_max,
cairo_direction_t dir)
{
if (cairo_status (cr))
return;
while (angle_max - angle_min > 4 * M_PI)
angle_max -= 2 * M_PI;
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
if (dir == CAIRO_DIRECTION_FORWARD) {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
} else {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_mid, angle_max,
dir);
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
dir);
}
} else if (angle_max != angle_min) {
cairo_matrix_t ctm;
int i, segments;
double angle, angle_step;
cairo_get_matrix (cr, &ctm);
segments = _arc_segments_needed (angle_max - angle_min,
radius, &ctm,
cairo_get_tolerance (cr));
angle_step = (angle_max - angle_min) / (double) segments;
if (dir == CAIRO_DIRECTION_FORWARD) {
angle = angle_min;
} else {
angle = angle_max;
angle_step = - angle_step;
}
for (i = 0; i < segments; i++, angle += angle_step) {
_cairo_arc_segment (cr, xc, yc,
radius,
angle,
angle + angle_step);
}
}
}
/**
* _cairo_arc_path
* @cr: a cairo context
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
*
* Compute a path for the given arc and append it onto the current
* path within @cr. The arc will be accurate within the current
* tolerance and given the current transformation.
**/
void
_cairo_arc_path (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle1, angle2,
CAIRO_DIRECTION_FORWARD);
}
/**
* _cairo_arc_path_negative:
* @xc: X position of the center of the arc
* @yc: Y position of the center of the arc
* @radius: the radius of the arc
* @angle1: the start angle, in radians
* @angle2: the end angle, in radians
* @ctm: the current transformation matrix
* @tolerance: the current tolerance value
* @path: the path onto which the arc will be appended
*
* Compute a path for the given arc (defined in the negative
* direction) and append it onto the current path within @cr. The arc
* will be accurate within the current tolerance and given the current
* transformation.
**/
void
_cairo_arc_path_negative (cairo_t *cr,
double xc,
double yc,
double radius,
double angle1,
double angle2)
{
_cairo_arc_in_direction (cr, xc, yc,
radius,
angle2, angle1,
CAIRO_DIRECTION_REVERSE);
}

View file

@ -0,0 +1,492 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
/**
* _cairo_array_init:
*
* Initialize a new #cairo_array_t object to store objects each of size
* @element_size.
*
* The #cairo_array_t object provides grow-by-doubling storage. It
* never interprets the data passed to it, nor does it provide any
* sort of callback mechanism for freeing resources held onto by
* stored objects.
*
* When finished using the array, _cairo_array_fini() should be
* called to free resources allocated during use of the array.
**/
void
_cairo_array_init (cairo_array_t *array, int element_size)
{
array->size = 0;
array->num_elements = 0;
array->element_size = element_size;
array->elements = NULL;
array->is_snapshot = FALSE;
}
/**
* _cairo_array_init_snapshot:
* @array: A #cairo_array_t to be initialized as a snapshot
* @other: The #cairo_array_t from which to create the snapshot
*
* Initialize @array as an immutable copy of @other. It is an error to
* call an array-modifying function (other than _cairo_array_fini) on
* @array after calling this function.
**/
void
_cairo_array_init_snapshot (cairo_array_t *array,
const cairo_array_t *other)
{
array->size = other->size;
array->num_elements = other->num_elements;
array->element_size = other->element_size;
array->elements = other->elements;
array->is_snapshot = TRUE;
}
/**
* _cairo_array_fini:
* @array: A #cairo_array_t
*
* Free all resources associated with @array. After this call, @array
* should not be used again without a subsequent call to
* _cairo_array_init() again first.
**/
void
_cairo_array_fini (cairo_array_t *array)
{
if (array->is_snapshot)
return;
if (array->elements) {
free (* array->elements);
free (array->elements);
}
}
/**
* _cairo_array_grow_by:
* @array: a #cairo_array_t
*
* Increase the size of @array (if needed) so that there are at least
* @additional free spaces in the array. The actual size of the array
* is always increased by doubling as many times as necessary.
**/
cairo_status_t
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
{
char *new_elements;
unsigned int old_size = array->size;
unsigned int required_size = array->num_elements + additional;
unsigned int new_size;
assert (! array->is_snapshot);
/* check for integer overflow */
if (required_size > INT_MAX || required_size < array->num_elements)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (required_size <= old_size)
return CAIRO_STATUS_SUCCESS;
if (old_size == 0)
new_size = 1;
else
new_size = old_size * 2;
while (new_size < required_size)
new_size = new_size * 2;
if (array->elements == NULL) {
array->elements = malloc (sizeof (char *));
if (array->elements == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*array->elements = NULL;
}
array->size = new_size;
new_elements = _cairo_realloc_ab (*array->elements,
array->size, array->element_size);
if (new_elements == NULL) {
array->size = old_size;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
*array->elements = new_elements;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_truncate:
* @array: a #cairo_array_t
*
* Truncate size of the array to @num_elements if less than the
* current size. No memory is actually freed. The stored objects
* beyond @num_elements are simply "forgotten".
**/
void
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
{
assert (! array->is_snapshot);
if (num_elements < array->num_elements)
array->num_elements = num_elements;
}
/**
* _cairo_array_index:
* @array: a #cairo_array_t
* Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
* pointer may be used for further direct indexing with []. For
* example:
*
* <informalexample><programlisting>
* cairo_array_t array;
* double *values;
*
* _cairo_array_init (&array, sizeof(double));
* ... calls to _cairo_array_append() here ...
*
* values = _cairo_array_index (&array, 0);
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... use values[i] here ...
* </programlisting></informalexample>
**/
void *
_cairo_array_index (cairo_array_t *array, unsigned int index)
{
/* We allow an index of 0 for the no-elements case.
* This makes for cleaner calling code which will often look like:
*
* elements = _cairo_array_index (array, num_elements);
* for (i=0; i < num_elements; i++) {
* ... use elements[i] here ...
* }
*
* which in the num_elements==0 case gets the NULL pointer here,
* but never dereferences it.
*/
if (index == 0 && array->num_elements == 0)
return NULL;
assert (index < array->num_elements);
return (void *) &(*array->elements)[index * array->element_size];
}
/**
* _cairo_array_copy_element:
* @array: a #cairo_array_t
*
* Copy a single element out of the array from index @index into the
* location pointed to by @dst.
**/
void
_cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
{
memcpy (dst, _cairo_array_index (array, index), array->element_size);
}
/**
* _cairo_array_append:
* @array: a #cairo_array_t
*
* Append a single item onto the array by growing the array by at
* least one element, then copying element_size bytes from @element
* into the array. The address of the resulting object within the
* array can be determined with:
*
* _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append (cairo_array_t *array,
const void *element)
{
assert (! array->is_snapshot);
return _cairo_array_append_multiple (array, element, 1);
}
/**
* _cairo_array_append:
* @array: a #cairo_array_t
*
* Append one or more items onto the array by growing the array by
* @num_elements, then copying @num_elements * element_size bytes from
* @elements into the array.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_append_multiple (cairo_array_t *array,
const void *elements,
int num_elements)
{
cairo_status_t status;
void *dest;
assert (! array->is_snapshot);
status = _cairo_array_allocate (array, num_elements, &dest);
if (status)
return status;
memcpy (dest, elements, num_elements * array->element_size);
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_allocate:
* @array: a #cairo_array_t
*
* Allocate space at the end of the array for @num_elements additional
* elements, providing the address of the new memory chunk in
* @elements. This memory will be unitialized, but will be accounted
* for in the return value of _cairo_array_num_elements().
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
_cairo_array_allocate (cairo_array_t *array,
unsigned int num_elements,
void **elements)
{
cairo_status_t status;
assert (! array->is_snapshot);
status = _cairo_array_grow_by (array, num_elements);
if (status)
return status;
assert (array->num_elements + num_elements <= array->size);
*elements = &(*array->elements)[array->num_elements * array->element_size];
array->num_elements += num_elements;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_array_num_elements:
* @array: a #cairo_array_t
* Returns: The number of elements stored in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
int
_cairo_array_num_elements (cairo_array_t *array)
{
return array->num_elements;
}
/**
* _cairo_array_size:
* @array: a #cairo_array_t
* Returns: The number of elements for which there is currently space
* allocated in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
**/
int
_cairo_array_size (cairo_array_t *array)
{
return array->size;
}
/* #cairo_user_data_array_t */
typedef struct {
const cairo_user_data_key_t *key;
void *user_data;
cairo_destroy_func_t destroy;
} cairo_user_data_slot_t;
/**
* _cairo_user_data_array_init:
* @array: a #cairo_user_data_array_t
*
* Initializes a #cairo_user_data_array_t structure for future
* use. After initialization, the array has no keys. Call
* _cairo_user_data_array_fini() to free any allocated memory
* when done using the array.
**/
void
_cairo_user_data_array_init (cairo_user_data_array_t *array)
{
_cairo_array_init (array, sizeof (cairo_user_data_slot_t));
}
/**
* _cairo_user_data_array_fini:
* @array: a #cairo_user_data_array_t
*
* Destroys all current keys in the user data array and deallocates
* any memory allocated for the array itself.
**/
void
_cairo_user_data_array_fini (cairo_user_data_array_t *array)
{
int i, num_slots;
cairo_user_data_slot_t *slots;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].user_data != NULL && slots[i].destroy != NULL)
slots[i].destroy (slots[i].user_data);
}
_cairo_array_fini (array);
}
/**
* _cairo_user_data_array_get_data:
* @array: a #cairo_user_data_array_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Returns user data previously attached using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
_cairo_user_data_array_get_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key)
{
int i, num_slots;
cairo_user_data_slot_t *slots;
/* We allow this to support degenerate objects such as cairo_surface_nil. */
if (array == NULL)
return NULL;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key)
return slots[i].user_data;
}
return NULL;
}
/**
* _cairo_user_data_array_set_data:
* @array: a #cairo_user_data_array_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach
* @destroy: a #cairo_destroy_func_t which will be called when the
* user data array is destroyed or when new user data is attached using the
* same key.
*
* Attaches user data to a user data array. To remove user data,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
_cairo_user_data_array_set_data (cairo_user_data_array_t *array,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
cairo_status_t status;
int i, num_slots;
cairo_user_data_slot_t *slots, *slot, new_slot;
if (user_data) {
new_slot.key = key;
new_slot.user_data = user_data;
new_slot.destroy = destroy;
} else {
new_slot.key = NULL;
new_slot.user_data = NULL;
new_slot.destroy = NULL;
}
slot = NULL;
num_slots = array->num_elements;
slots = _cairo_array_index (array, 0);
for (i = 0; i < num_slots; i++) {
if (slots[i].key == key) {
slot = &slots[i];
if (slot->destroy && slot->user_data)
slot->destroy (slot->user_data);
break;
}
if (user_data && slots[i].user_data == NULL) {
slot = &slots[i]; /* Have to keep searching for an exact match */
}
}
if (slot) {
*slot = new_slot;
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_array_append (array, &new_slot);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}

View file

@ -0,0 +1,104 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_ATOMIC_PRIVATE_H
#define CAIRO_ATOMIC_PRIVATE_H
# include "cairo-compiler-private.h"
#if HAVE_CONFIG_H
#include "config.h"
#endif
CAIRO_BEGIN_DECLS
#if HAVE_INTEL_ATOMIC_PRIMITIVES
#define HAS_ATOMIC_OPS 1
typedef int cairo_atomic_int_t;
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
#endif
#ifndef HAS_ATOMIC_OPS
typedef int cairo_atomic_int_t;
cairo_private void
_cairo_atomic_int_inc (int *x);
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x);
cairo_private int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
#endif
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
# include "cairo-compiler-private.h"
cairo_private int
_cairo_atomic_int_get (int *x);
cairo_private void
_cairo_atomic_int_set (int *x, int value);
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_set(x, value) ((*x) = value)
#endif
#define _cairo_status_set_error(status, err) do { \
/* hide compiler warnings about cairo_status_t != int (gcc treats its as \
* an unsigned integer instead, and about ignoring the return value. */ \
int ret__ = _cairo_atomic_int_cmpxchg ((int *) status, CAIRO_STATUS_SUCCESS, err); \
(void) ret__; \
} while (0)
CAIRO_END_DECLS
#endif

View file

@ -0,0 +1,96 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-atomic-private.h"
#include "cairo-mutex-private.h"
#ifndef HAS_ATOMIC_OPS
void
_cairo_atomic_int_inc (int *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x)
{
cairo_bool_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = --*x == 0;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
{
int ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
#endif
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
int
_cairo_atomic_int_get (int *x)
{
int ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
void
_cairo_atomic_int_set (int *x, int value)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x = value;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
#endif

View file

@ -0,0 +1,132 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
#include "cairoint.h"
#include "cairo-output-stream-private.h"
typedef struct _cairo_base85_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
unsigned char four_tuple[4];
int pending;
} cairo_base85_stream_t;
static void
_expand_four_tuple_to_five (unsigned char four_tuple[4],
unsigned char five_tuple[5],
cairo_bool_t *all_zero)
{
uint32_t value;
int digit, i;
value = four_tuple[0] << 24 | four_tuple[1] << 16 | four_tuple[2] << 8 | four_tuple[3];
if (all_zero)
*all_zero = TRUE;
for (i = 0; i < 5; i++) {
digit = value % 85;
if (digit != 0 && all_zero)
*all_zero = FALSE;
five_tuple[4-i] = digit + 33;
value = value / 85;
}
}
static cairo_status_t
_cairo_base85_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
const unsigned char *ptr = data;
unsigned char five_tuple[5];
cairo_bool_t is_zero;
while (length) {
stream->four_tuple[stream->pending++] = *ptr++;
length--;
if (stream->pending == 4) {
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, &is_zero);
if (is_zero)
_cairo_output_stream_write (stream->output, "z", 1);
else
_cairo_output_stream_write (stream->output, five_tuple, 5);
stream->pending = 0;
}
}
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_base85_stream_close (cairo_output_stream_t *base)
{
cairo_base85_stream_t *stream = (cairo_base85_stream_t *) base;
unsigned char five_tuple[5];
if (stream->pending) {
memset (stream->four_tuple + stream->pending, 0, 4 - stream->pending);
_expand_four_tuple_to_five (stream->four_tuple, five_tuple, NULL);
_cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
}
/* Mark end of base85 data */
_cairo_output_stream_printf (stream->output, "~>");
return _cairo_output_stream_get_status (stream->output);
}
cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output)
{
cairo_base85_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base85_stream_t));
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write,
_cairo_base85_stream_close);
stream->output = output;
stream->pending = 0;
return &stream->base;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Christian Biesinger <cbiesinger@web.de>
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Christian Biesinger
* <cbiesinger@web.de>
*
* Contributor(s):
*/
#ifndef CAIRO_BEOS_H
#define CAIRO_BEOS_H
#include "cairo.h"
#if CAIRO_HAS_BEOS_SURFACE
#include <View.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_beos_surface_create (BView* view);
cairo_public cairo_surface_t *
cairo_beos_surface_create_for_bitmap (BView* view,
BBitmap* bmp);
CAIRO_END_DECLS
#else /* CAIRO_HAS_BEOS_SURFACE */
# error Cairo was not compiled with support for the beos backend
#endif /* CAIRO_HAS_BEOS_SURFACE */
#endif /* CAIRO_BEOS_H */

View file

@ -0,0 +1,126 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#ifndef CAIRO_CACHE_PRIVATE_H
#define CAIRO_CACHE_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/**
* cairo_cache_entry_t:
*
* A #cairo_cache_entry_t contains both a key and a value for
* #cairo_cache_t. User-derived types for #cairo_cache_entry_t must
* have a #cairo_cache_entry_t as their first field. For example:
*
* typedef _my_entry {
* cairo_cache_entry_t base;
* ... Remainder of key and value fields here ..
* } my_entry_t;
*
* which then allows a pointer to my_entry_t to be passed to any of
* the #cairo_cache_t functions as follows without requiring a cast:
*
* _cairo_cache_insert (cache, &my_entry->base, size);
*
* IMPORTANT: The caller is responsible for initializing
* my_entry->base.hash with a hash code derived from the key. The
* essential property of the hash code is that keys_equal must never
* return %TRUE for two keys that have different hashes. The best hash
* code will reduce the frequency of two keys with the same code for
* which keys_equal returns %FALSE.
*
* The user must also initialize my_entry->base.size to indicate
* the size of the current entry. What units to use for size is
* entirely up to the caller, (though the same units must be used for
* the max_size parameter passed to _cairo_cache_create()). If all
* entries are close to the same size, the simplest thing to do is to
* just use units of "entries", (eg. set size==1 in all entries and
* set max_size to the number of entries which you want to be saved
* in the cache).
*
* Which parts of the entry make up the "key" and which part make up
* the value are entirely up to the caller, (as determined by the
* computation going into base.hash as well as the keys_equal
* function). A few of the #cairo_cache_t functions accept an entry which
* will be used exclusively as a "key", (indicated by a parameter name
* of key). In these cases, the value-related fields of the entry need
* not be initialized if so desired.
**/
typedef struct _cairo_cache_entry {
unsigned long hash;
unsigned long size;
} cairo_cache_entry_t;
typedef cairo_bool_t
(*cairo_cache_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef void
(*cairo_cache_callback_func_t) (void *entry,
void *closure);
cairo_private cairo_cache_t *
_cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
cairo_destroy_func_t entry_destroy,
unsigned long max_size);
cairo_private void
_cairo_cache_destroy (cairo_cache_t *cache);
cairo_private void
_cairo_cache_freeze (cairo_cache_t *cache);
cairo_private void
_cairo_cache_thaw (cairo_cache_t *cache);
cairo_private cairo_bool_t
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key,
cairo_cache_entry_t **entry_return);
cairo_private cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
cairo_private void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure);
#endif

View file

@ -0,0 +1,363 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
static void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional);
static cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
cairo_cache_keys_equal_func_t keys_equal,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
cache->hash_table = _cairo_hash_table_create (keys_equal);
if (cache->hash_table == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cache->entry_destroy = entry_destroy;
cache->max_size = max_size;
cache->size = 0;
cache->freeze_count = 0;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_cache_fini (cairo_cache_t *cache)
{
cairo_cache_entry_t *entry;
/* We have to manually remove all entries from the cache ourselves
* rather than relying on _cairo_hash_table_destroy() to do that
* since otherwise the cache->entry_destroy callback would not get
* called on each entry. */
while (1) {
entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
if (entry == NULL)
break;
_cairo_cache_remove (cache, entry);
}
_cairo_hash_table_destroy (cache->hash_table);
cache->size = 0;
}
/**
* _cairo_cache_create:
* @keys_equal: a function to return %TRUE if two keys are equal
* @entry_destroy: destroy notifier for cache entries
* @max_size: the maximum size for this cache
* Returns: the newly created #cairo_cache_t
*
* Creates a new cache using the keys_equal() function to determine
* the equality of entries.
*
* Data is provided to the cache in the form of user-derived version
* of #cairo_cache_entry_t. A cache entry must be able to hold hash
* code, a size, and the key/value pair being stored in the
* cache. Sometimes only the key will be necessary, (as in
* _cairo_cache_lookup()), and in these cases the value portion of the
* entry need not be initialized.
*
* The units for max_size can be chosen by the caller, but should be
* consistent with the units of the size field of cache entries. When
* adding an entry with _cairo_cache_insert() if the total size of
* entries in the cache would exceed max_size then entries will be
* removed at random until the new entry would fit or the cache is
* empty. Then the new entry is inserted.
*
* There are cases in which the automatic removal of entries is
* undesired. If the cache entries have reference counts, then it is a
* simple matter to use the reference counts to ensure that entries
* continue to live even after being ejected from the cache. However,
* in some cases the memory overhead of adding a reference count to
* the entry would be objectionable. In such cases, the
* _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
* used to establish a window during which no automatic removal of
* entries will occur.
**/
cairo_cache_t *
_cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
cairo_destroy_func_t entry_destroy,
unsigned long max_size)
{
cairo_status_t status;
cairo_cache_t *cache;
cache = malloc (sizeof (cairo_cache_t));
if (cache == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size);
if (status) {
free (cache);
return NULL;
}
return cache;
}
/**
* _cairo_cache_destroy:
* @cache: a cache to destroy
*
* Immediately destroys the given cache, freeing all resources
* associated with it. As part of this process, the entry_destroy()
* function, (as passed to _cairo_cache_create()), will be called for
* each entry in the cache.
**/
void
_cairo_cache_destroy (cairo_cache_t *cache)
{
_cairo_cache_fini (cache);
free (cache);
}
/**
* _cairo_cache_freeze:
* @cache: a cache with some precious entries in it (or about to be
* added)
*
* Disable the automatic ejection of entries from the cache. For as
* long as the cache is "frozen", calls to _cairo_cache_insert() will
* add new entries to the cache regardless of how large the cache
* grows. See _cairo_cache_thaw().
*
* Note: Multiple calls to _cairo_cache_freeze() will stack, in that
* the cache will remain "frozen" until a corresponding number of
* calls are made to _cairo_cache_thaw().
**/
void
_cairo_cache_freeze (cairo_cache_t *cache)
{
assert (cache->freeze_count >= 0);
cache->freeze_count++;
}
/**
* _cairo_cache_thaw:
* @cache: a cache, just after the entries in it have become less
* precious
*
* Cancels the effects of _cairo_cache_freeze().
*
* When a number of calls to _cairo_cache_thaw() is made corresponding
* to the number of calls to _cairo_cache_freeze() the cache will no
* longer be "frozen". If the cache had grown larger than max_size
* while frozen, entries will immediately be ejected (by random) from
* the cache until the cache is smaller than max_size. Also, the
* automatic ejection of entries on _cairo_cache_insert() will resume.
**/
void
_cairo_cache_thaw (cairo_cache_t *cache)
{
assert (cache->freeze_count > 0);
cache->freeze_count--;
if (cache->freeze_count == 0)
_cairo_cache_shrink_to_accommodate (cache, 0);
}
/**
* _cairo_cache_lookup:
* @cache: a cache
* @key: the key of interest
* @entry_return: pointer for return value
*
* Performs a lookup in @cache looking for an entry which has a key
* that matches @key, (as determined by the keys_equal() function
* passed to _cairo_cache_create()).
*
* Return value: %TRUE if there is an entry in the cache that matches
* @key, (which will now be in *entry_return). %FALSE otherwise, (in
* which case *entry_return will be %NULL).
**/
cairo_bool_t
_cairo_cache_lookup (cairo_cache_t *cache,
cairo_cache_entry_t *key,
cairo_cache_entry_t **entry_return)
{
return _cairo_hash_table_lookup (cache->hash_table,
(cairo_hash_entry_t *) key,
(cairo_hash_entry_t **) entry_return);
}
/**
* _cairo_cache_remove_random:
* @cache: a cache
*
* Remove a random entry from the cache.
*
* Return value: %TRUE if an entry was successfully removed.
* %FALSE if there are no entries that can be removed.
**/
static cairo_bool_t
_cairo_cache_remove_random (cairo_cache_t *cache)
{
cairo_cache_entry_t *entry;
entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
if (entry == NULL)
return FALSE;
_cairo_cache_remove (cache, entry);
return TRUE;
}
/**
* _cairo_cache_shrink_to_accommodate:
* @cache: a cache
* @additional: additional size requested in bytes
*
* If cache is not frozen, eject entries randomly until the size of
* the cache is at least @additional bytes less than
* cache->max_size. That is, make enough room to accommodate a new
* entry of size @additional.
**/
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
unsigned long additional)
{
if (cache->freeze_count)
return;
while (cache->size + additional > cache->max_size) {
if (! _cairo_cache_remove_random (cache))
return;
}
}
/**
* _cairo_cache_insert:
* @cache: a cache
* @entry: an entry to be inserted
*
* Insert @entry into the cache. If an entry exists in the cache with
* a matching key, then the old entry will be removed first, (and the
* entry_destroy() callback will be called on it).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cairo_status_t status;
_cairo_cache_shrink_to_accommodate (cache, entry->size);
status = _cairo_hash_table_insert (cache->hash_table,
(cairo_hash_entry_t *) entry);
if (status)
return status;
cache->size += entry->size;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_cache_remove:
* @cache: a cache
* @entry: an entry that exists in the cache
*
* Remove an existing entry from the cache.
*
* (Note: If any caller wanted access to a non-static version of this
* function, an improved version would require only a key rather than
* an entry. Fixing that would require fixing _cairo_hash_table_remove
* to return (a copy of?) the entry being removed.)
**/
static void
_cairo_cache_remove (cairo_cache_t *cache,
cairo_cache_entry_t *entry)
{
cache->size -= entry->size;
_cairo_hash_table_remove (cache->hash_table,
(cairo_hash_entry_t *) entry);
if (cache->entry_destroy)
cache->entry_destroy (entry);
}
/**
* _cairo_cache_foreach:
* @cache: a cache
* @cache_callback: function to be called for each entry
* @closure: additional argument to be passed to @cache_callback
*
* Call @cache_callback for each entry in the cache, in a
* non-specified order.
**/
void
_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure)
{
_cairo_hash_table_foreach (cache->hash_table,
cache_callback,
closure);
}
unsigned long
_cairo_hash_string (const char *c)
{
/* This is the djb2 hash. */
unsigned long hash = 5381;
while (c && *c)
hash = ((hash << 5) + hash) + *c++;
return hash;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,136 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
*/
#ifndef CAIRO_CLIP_PRIVATE_H
#define CAIRO_CLIP_PRIVATE_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-region-private.h"
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
struct _cairo_clip_path {
cairo_reference_count_t ref_count;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
cairo_clip_path_t *prev;
};
struct _cairo_clip {
cairo_clip_mode_t mode;
cairo_bool_t all_clipped;
/*
* Mask-based clipping for cases where the backend
* clipping isn't sufficiently able.
*
* The rectangle here represents the
* portion of the destination surface that this
* clip surface maps to, it does not
* represent the extents of the clip region or
* clip paths
*/
cairo_surface_t *surface;
cairo_rectangle_int_t surface_rect;
/*
* Surface clip serial number to store
* in the surface when this clip is set
*/
unsigned int serial;
/*
* A clip region that can be placed in the surface
*/
cairo_region_t region;
cairo_bool_t has_region;
/*
* If the surface supports path clipping, we store the list of
* clipping paths that has been set here as a linked list.
*/
cairo_clip_path_t *path;
};
cairo_private void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
cairo_private cairo_status_t
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
cairo_clip_t *other,
cairo_surface_t *target);
cairo_private void
_cairo_clip_reset (cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
cairo_rectangle_int_t *rectangle);
cairo_private cairo_status_t
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
cairo_region_t *region);
cairo_private cairo_status_t
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
cairo_operator_t op,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents);
cairo_private void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,
cairo_fixed_t ty);
cairo_private cairo_rectangle_list_t*
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate);
#endif /* CAIRO_CLIP_PRIVATE_H */

View file

@ -0,0 +1,858 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
*/
#include "cairoint.h"
#include "cairo-clip-private.h"
static cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
static void
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
{
if (target)
clip->mode = _cairo_surface_get_clip_mode (target);
else
clip->mode = CAIRO_CLIP_MODE_MASK;
clip->all_clipped = FALSE;
clip->surface = NULL;
clip->surface_rect.x = 0;
clip->surface_rect.y = 0;
clip->surface_rect.width = 0;
clip->surface_rect.height = 0;
clip->serial = 0;
_cairo_region_init (&clip->region);
clip->has_region = FALSE;
clip->path = NULL;
}
cairo_status_t
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{
clip->mode = other->mode;
clip->all_clipped = other->all_clipped;
clip->surface = cairo_surface_reference (other->surface);
clip->surface_rect = other->surface_rect;
clip->serial = other->serial;
_cairo_region_init (&clip->region);
if (other->has_region) {
cairo_status_t status;
status = _cairo_region_copy (&clip->region, &other->region);
if (status) {
_cairo_region_fini (&clip->region);
cairo_surface_destroy (clip->surface);
return status;
}
clip->has_region = TRUE;
} else {
clip->has_region = FALSE;
}
clip->path = _cairo_clip_path_reference (other->path);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_clip_reset (cairo_clip_t *clip)
{
clip->all_clipped = FALSE;
/* destroy any existing clip-region artifacts */
cairo_surface_destroy (clip->surface);
clip->surface = NULL;
clip->serial = 0;
if (clip->has_region) {
/* _cairo_region_fini just releases the resources used but
* doesn't bother with leaving the region in a valid state.
* So _cairo_region_init has to be called afterwards. */
_cairo_region_fini (&clip->region);
_cairo_region_init (&clip->region);
clip->has_region = FALSE;
}
_cairo_clip_path_destroy (clip->path);
clip->path = NULL;
}
static void
_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
{
_cairo_clip_reset (clip);
clip->all_clipped = TRUE;
clip->serial = _cairo_surface_allocate_clip_serial (target);
}
static cairo_status_t
_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
cairo_rectangle_int_t *rectangle)
{
while (clip_path) {
cairo_status_t status;
cairo_traps_t traps;
cairo_box_t extents;
cairo_rectangle_int_t extents_rect;
_cairo_box_from_rectangle (&extents, rectangle);
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &extents);
status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
&traps);
if (status) {
_cairo_traps_fini (&traps);
return status;
}
_cairo_traps_extents (&traps, &extents);
_cairo_traps_fini (&traps);
_cairo_box_round_to_rectangle (&extents, &extents_rect);
if (! _cairo_rectangle_intersect (rectangle, &extents_rect))
return CAIRO_STATUS_SUCCESS;
clip_path = clip_path->prev;
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
cairo_rectangle_int_t *rectangle)
{
cairo_status_t status;
cairo_bool_t is_empty;
if (!clip)
return CAIRO_STATUS_SUCCESS;
if (clip->all_clipped) {
*rectangle = clip->surface_rect;
return CAIRO_STATUS_SUCCESS;
}
if (clip->path) {
status = _cairo_clip_path_intersect_to_rectangle (clip->path,
rectangle);
if (status)
return status;
}
if (clip->has_region) {
cairo_region_t intersection;
_cairo_region_init_rect (&intersection, rectangle);
status = _cairo_region_intersect (&intersection, &clip->region,
&intersection);
if (!status)
_cairo_region_get_extents (&intersection, rectangle);
_cairo_region_fini (&intersection);
if (status)
return status;
}
if (clip->surface)
is_empty = _cairo_rectangle_intersect (rectangle, &clip->surface_rect);
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_clip_intersect_to_region (cairo_clip_t *clip,
cairo_region_t *region)
{
cairo_status_t status;
if (!clip)
return CAIRO_STATUS_SUCCESS;
if (clip->all_clipped) {
cairo_region_t clip_rect;
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
status = _cairo_region_intersect (region, &clip_rect, region);
_cairo_region_fini (&clip_rect);
return status;
}
if (clip->path) {
/* Intersect clip path into region. */
}
if (clip->has_region) {
status = _cairo_region_intersect (region, &clip->region, region);
if (status)
return status;
}
if (clip->surface) {
cairo_region_t clip_rect;
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
status = _cairo_region_intersect (region, &clip_rect, region);
_cairo_region_fini (&clip_rect);
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}
/* Combines the region of clip->surface given by extents in
* device backend coordinates into the given temporary surface,
* which has its origin at dst_x, dst_y in backend coordinates
*/
cairo_status_t
_cairo_clip_combine_to_surface (cairo_clip_t *clip,
cairo_operator_t op,
cairo_surface_t *dst,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents)
{
cairo_surface_pattern_t pattern;
cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_for_surface (&pattern, clip->surface);
status = _cairo_surface_composite (op,
&pattern.base,
NULL,
dst,
extents->x - clip->surface_rect.x,
extents->y - clip->surface_rect.y,
0, 0,
extents->x - dst_x,
extents->y - dst_y,
extents->width, extents->height);
_cairo_pattern_fini (&pattern.base);
return status;
}
static cairo_status_t
_cairo_clip_intersect_path (cairo_clip_t *clip,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_clip_path_t *clip_path;
cairo_status_t status;
if (clip->mode != CAIRO_CLIP_MODE_PATH)
return CAIRO_INT_STATUS_UNSUPPORTED;
clip_path = malloc (sizeof (cairo_clip_path_t));
if (clip_path == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (status) {
free (clip_path);
return status;
}
CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance;
clip_path->antialias = antialias;
clip_path->prev = clip->path;
clip->path = clip_path;
return CAIRO_STATUS_SUCCESS;
}
static cairo_clip_path_t *
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
{
if (clip_path == NULL)
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
_cairo_reference_count_inc (&clip_path->ref_count);
return clip_path;
}
static void
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
{
if (clip_path == NULL)
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
return;
_cairo_path_fixed_fini (&clip_path->path);
_cairo_clip_path_destroy (clip_path->prev);
free (clip_path);
}
static cairo_int_status_t
_cairo_clip_intersect_region (cairo_clip_t *clip,
cairo_traps_t *traps,
cairo_surface_t *target)
{
cairo_region_t region;
cairo_int_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (clip->mode != CAIRO_CLIP_MODE_REGION)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_traps_extract_region (traps, &region);
if (status)
return status;
if (!clip->has_region) {
status = _cairo_region_copy (&clip->region, &region);
if (status == CAIRO_STATUS_SUCCESS)
clip->has_region = TRUE;
} else {
cairo_region_t intersection;
_cairo_region_init (&intersection);
status = _cairo_region_intersect (&intersection,
&clip->region,
&region);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_region_copy (&clip->region, &intersection);
_cairo_region_fini (&intersection);
}
clip->serial = _cairo_surface_allocate_clip_serial (target);
_cairo_region_fini (&region);
if (! _cairo_region_not_empty (&clip->region))
_cairo_clip_set_all_clipped (clip, target);
return status;
}
static cairo_status_t
_cairo_clip_intersect_mask (cairo_clip_t *clip,
cairo_traps_t *traps,
cairo_antialias_t antialias,
cairo_surface_t *target)
{
cairo_pattern_union_t pattern;
cairo_box_t extents;
cairo_rectangle_int_t surface_rect, target_rect;
cairo_surface_t *surface = NULL;
cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
/* Represent the clip as a mask surface. We create a new surface
* the size of the intersection of the old mask surface and the
* extents of the new clip path. */
_cairo_traps_extents (traps, &extents);
_cairo_box_round_to_rectangle (&extents, &surface_rect);
if (clip->surface != NULL) {
if (! _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
goto DONE;
}
/* Intersect with the target surface rectangle so we don't use
* more memory and time than we need to. */
status = _cairo_surface_get_extents (target, &target_rect);
if (status == CAIRO_STATUS_SUCCESS) {
if (! _cairo_rectangle_intersect (&surface_rect, &target_rect))
goto DONE;
}
if (surface_rect.width == 0 || surface_rect.height == 0)
goto DONE;
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
/* The clipping operation should ideally be something like the following to
* avoid having to do as many passes over the data
if (clip->surface != NULL) {
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
} else {
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
}
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
&pattern.base,
surface,
antialias,
0, 0,
0, 0,
surface_rect.width,
surface_rect.height,
traps->traps,
traps->num_traps);
However this operation is not accelerated by pixman
I believe the best possible operation would probably an unbounded SRC
operator. Using SRC we could potentially avoid having to initialize
the surface which would be ideal from an efficiency point of view.
However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is
bounded by the mask.
*/
surface = _cairo_surface_create_similar_solid (target,
CAIRO_CONTENT_ALPHA,
surface_rect.width,
surface_rect.height,
CAIRO_COLOR_TRANSPARENT);
if (surface->status) {
_cairo_pattern_fini (&pattern.base);
return surface->status;
}
/* Render the new clipping path into the new mask surface. */
_cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
&pattern.base,
surface,
antialias,
0, 0,
0, 0,
surface_rect.width,
surface_rect.height,
traps->traps,
traps->num_traps);
_cairo_pattern_fini (&pattern.base);
if (status) {
cairo_surface_destroy (surface);
return status;
}
/* If there was a clip surface already, combine it with the new
* mask surface using the IN operator, so we get the intersection
* of the old and new clipping paths. */
if (clip->surface != NULL) {
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
&pattern.base,
NULL,
surface,
surface_rect.x - clip->surface_rect.x,
surface_rect.y - clip->surface_rect.y,
0, 0,
0, 0,
surface_rect.width,
surface_rect.height);
_cairo_pattern_fini (&pattern.base);
if (status) {
cairo_surface_destroy (surface);
return status;
}
}
DONE:
cairo_surface_destroy (clip->surface);
clip->surface = surface;
clip->surface_rect = surface_rect;
clip->serial = _cairo_surface_allocate_clip_serial (target);
if (surface_rect.width == 0 || surface_rect.height == 0)
_cairo_clip_set_all_clipped (clip, target);
return status;
}
cairo_status_t
_cairo_clip_clip (cairo_clip_t *clip,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
cairo_surface_t *target)
{
cairo_status_t status;
cairo_rectangle_int_t rectangle;
cairo_traps_t traps;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
/* catch the empty clip path */
if (! path->has_current_point) {
_cairo_clip_set_all_clipped (clip, target);
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_clip_intersect_path (clip,
path, fill_rule, tolerance,
antialias);
if (status == CAIRO_STATUS_SUCCESS)
clip->serial = _cairo_surface_allocate_clip_serial (target);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_traps_init (&traps);
/* Limit the traps to the target surface
* - so we don't add more traps than needed. */
status = _cairo_surface_get_extents (target, &rectangle);
if (status == CAIRO_STATUS_SUCCESS) {
cairo_box_t box;
_cairo_box_from_rectangle (&box, &rectangle);
_cairo_traps_limit (&traps, &box);
}
status = _cairo_path_fixed_fill_to_traps (path,
fill_rule,
tolerance,
&traps);
if (status)
goto bail;
status = _cairo_clip_intersect_region (clip, &traps, target);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto bail;
status = _cairo_clip_intersect_mask (clip, &traps, antialias, target);
bail:
_cairo_traps_fini (&traps);
return status;
}
void
_cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx,
cairo_fixed_t ty)
{
if (clip->all_clipped)
return;
if (clip->has_region) {
_cairo_region_translate (&clip->region,
_cairo_fixed_integer_part (tx),
_cairo_fixed_integer_part (ty));
}
if (clip->surface) {
clip->surface_rect.x += _cairo_fixed_integer_part (tx);
clip->surface_rect.y += _cairo_fixed_integer_part (ty);
}
if (clip->path) {
cairo_clip_path_t *clip_path = clip->path;
cairo_matrix_t matrix;
cairo_matrix_init_translate (&matrix,
_cairo_fixed_to_double (tx),
_cairo_fixed_to_double (ty));
while (clip_path) {
_cairo_path_fixed_transform (&clip_path->path, &matrix);
clip_path = clip_path->prev;
}
}
}
static cairo_status_t
_cairo_clip_path_reapply_clip_path (cairo_clip_t *clip,
cairo_clip_path_t *clip_path)
{
cairo_status_t status;
if (clip_path->prev) {
status = _cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
return _cairo_clip_intersect_path (clip,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
}
cairo_status_t
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
cairo_clip_t *other,
cairo_surface_t *target)
{
cairo_status_t status;
_cairo_clip_init (clip, target);
if (other->mode != clip->mode) {
/* We should reapply the original clip path in this case, and let
* whatever the right handling is happen */
} else {
if (other->has_region) {
status = _cairo_region_copy (&clip->region, &other->region);
if (status)
goto BAIL;
clip->has_region = TRUE;
}
if (other->surface) {
int dx, dy;
status = _cairo_surface_clone_similar (target, other->surface,
0,
0,
other->surface_rect.width,
other->surface_rect.height,
&dx, &dy,
&clip->surface);
if (status)
goto BAIL;
clip->surface_rect = other->surface_rect;
/* src offset was 0, so we expect an exact replica of the surface */
assert (dx == 0);
assert (dy == 0);
}
if (other->path) {
status = _cairo_clip_path_reapply_clip_path (clip, other->path);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
goto BAIL;
}
}
return CAIRO_STATUS_SUCCESS;
BAIL:
if (clip->has_region)
_cairo_region_fini (&clip->region);
if (clip->surface)
cairo_surface_destroy (clip->surface);
return status;
}
const cairo_rectangle_list_t _cairo_rectangles_nil =
{ CAIRO_STATUS_NO_MEMORY, NULL, 0 };
static const cairo_rectangle_list_t _cairo_rectangles_not_representable =
{ CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, NULL, 0 };
static cairo_bool_t
_cairo_clip_int_rect_to_user (cairo_gstate_t *gstate,
cairo_rectangle_int_t *clip_rect,
cairo_rectangle_t *user_rect)
{
cairo_bool_t is_tight;
double x1 = clip_rect->x;
double y1 = clip_rect->y;
double x2 = clip_rect->x + (int) clip_rect->width;
double y2 = clip_rect->y + (int) clip_rect->height;
_cairo_gstate_backend_to_user_rectangle (gstate,
&x1, &y1, &x2, &y2,
&is_tight);
user_rect->x = x1;
user_rect->y = y1;
user_rect->width = x2 - x1;
user_rect->height = y2 - y1;
return is_tight;
}
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL;
int n_boxes = 0;
if (clip->all_clipped)
goto DONE;
if (clip->path || clip->surface) {
_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
}
if (clip->has_region) {
cairo_box_int_t *boxes;
int i;
if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes))
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
if (n_boxes) {
rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
if (rectangles == NULL) {
_cairo_region_boxes_fini (&clip->region, boxes);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
for (i = 0; i < n_boxes; ++i) {
cairo_rectangle_int_t clip_rect;
clip_rect.x = boxes[i].p1.x;
clip_rect.y = boxes[i].p1.y;
clip_rect.width = boxes[i].p2.x - boxes[i].p1.x;
clip_rect.height = boxes[i].p2.y - boxes[i].p1.y;
if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
_cairo_region_boxes_fini (&clip->region, boxes);
free (rectangles);
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
}
}
}
_cairo_region_boxes_fini (&clip->region, boxes);
} else {
cairo_rectangle_int_t extents;
n_boxes = 1;
rectangles = malloc(sizeof (cairo_rectangle_t));
if (rectangles == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) ||
!_cairo_clip_int_rect_to_user(gstate, &extents, rectangles))
{
_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
free (rectangles);
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
}
}
DONE:
list = malloc (sizeof (cairo_rectangle_list_t));
if (list == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (rectangles);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
list->status = CAIRO_STATUS_SUCCESS;
list->rectangles = rectangles;
list->num_rectangles = n_boxes;
return list;
}
/**
* cairo_rectangle_list_destroy:
* @rectangle_list: a rectangle list, as obtained from cairo_copy_clip_rectangles()
*
* Unconditionally frees @rectangle_list and all associated
* references. After this call, the @rectangle_list pointer must not
* be dereferenced.
*
* Since: 1.4
**/
void
cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list)
{
if (rectangle_list == NULL || rectangle_list == &_cairo_rectangles_nil ||
rectangle_list == &_cairo_rectangles_not_representable)
return;
free (rectangle_list->rectangles);
free (rectangle_list);
}

View file

@ -0,0 +1,175 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
static cairo_color_t const cairo_color_white = {
1.0, 1.0, 1.0, 1.0,
0xffff, 0xffff, 0xffff, 0xffff
};
static cairo_color_t const cairo_color_black = {
0.0, 0.0, 0.0, 1.0,
0x0, 0x0, 0x0, 0xffff
};
static cairo_color_t const cairo_color_transparent = {
0.0, 0.0, 0.0, 0.0,
0x0, 0x0, 0x0, 0x0
};
static cairo_color_t const cairo_color_magenta = {
1.0, 0.0, 1.0, 1.0,
0xffff, 0x0, 0xffff, 0xffff
};
const cairo_color_t *
_cairo_stock_color (cairo_stock_t stock)
{
switch (stock) {
case CAIRO_STOCK_WHITE:
return &cairo_color_white;
case CAIRO_STOCK_BLACK:
return &cairo_color_black;
case CAIRO_STOCK_TRANSPARENT:
return &cairo_color_transparent;
}
ASSERT_NOT_REACHED;
/* If the user can get here somehow, give a color that indicates a
* problem. */
return &cairo_color_magenta;
}
void
_cairo_color_init (cairo_color_t *color)
{
*color = cairo_color_white;
}
void
_cairo_color_init_rgb (cairo_color_t *color,
double red, double green, double blue)
{
_cairo_color_init_rgba (color, red, green, blue, 1.0);
}
/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
* The conversion is designed to divide the input range into 65536
* equally-sized regions. This is achieved by multiplying by 65536 and
* then special-casing the result of an input value of 1.0 so that it
* maps to 65535 instead of 65536.
*/
uint16_t
_cairo_color_double_to_short (double d)
{
uint32_t i;
i = (uint32_t) (d * 65536);
i -= (i >> 16);
return i;
}
static void
_cairo_color_compute_shorts (cairo_color_t *color)
{
color->red_short = _cairo_color_double_to_short (color->red * color->alpha);
color->green_short = _cairo_color_double_to_short (color->green * color->alpha);
color->blue_short = _cairo_color_double_to_short (color->blue * color->alpha);
color->alpha_short = _cairo_color_double_to_short (color->alpha);
}
void
_cairo_color_init_rgba (cairo_color_t *color,
double red, double green, double blue,
double alpha)
{
color->red = red;
color->green = green;
color->blue = blue;
color->alpha = alpha;
_cairo_color_compute_shorts (color);
}
void
_cairo_color_multiply_alpha (cairo_color_t *color,
double alpha)
{
color->alpha *= alpha;
_cairo_color_compute_shorts (color);
}
void
_cairo_color_get_rgba (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red;
*green = color->green;
*blue = color->blue;
*alpha = color->alpha;
}
void
_cairo_color_get_rgba_premultiplied (cairo_color_t *color,
double *red,
double *green,
double *blue,
double *alpha)
{
*red = color->red * color->alpha;
*green = color->green * color->alpha;
*blue = color->blue * color->alpha;
*alpha = color->alpha;
}
cairo_bool_t
_cairo_color_equal (const cairo_color_t *color_a,
const cairo_color_t *color_b)
{
if (color_a == color_b)
return TRUE;
return color_a->red_short == color_b->red_short &&
color_a->green_short == color_b->green_short &&
color_a->blue_short == color_b->blue_short &&
color_a->alpha_short == color_b->alpha_short;
}

View file

@ -0,0 +1,162 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_COMPILER_PRIVATE_H
#define CAIRO_COMPILER_PRIVATE_H
#include "cairo.h"
#if HAVE_CONFIG_H
#include "config.h"
#endif
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal))
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
# define slim_hidden_ulp2(x) #x
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
#else
# define slim_hidden_proto(name) int _cairo_dummy_prototype(void)
# define slim_hidden_proto_no_warn(name) int _cairo_dummy_prototype(void)
# define slim_hidden_def(name) int _cairo_dummy_prototype(void)
#endif
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
__attribute__((__format__(__printf__, fmt_index, va_index)))
#else
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
#endif
/* slim_internal.h */
#define CAIRO_HAS_HIDDEN_SYMBOLS 1
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
#define cairo_private_no_warn __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define cairo_private_no_warn __hidden
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
#define cairo_private_no_warn
#undef CAIRO_HAS_HIDDEN_SYMBOLS
#endif
#ifndef WARN_UNUSED_RESULT
#define WARN_UNUSED_RESULT
#endif
/* Add attribute(warn_unused_result) if supported */
#define cairo_warn WARN_UNUSED_RESULT
#define cairo_private cairo_private_no_warn cairo_warn
/* This macro allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
some platforms --- tough.
Meanwhile, new definitions in the public header file break the
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
function.
*/
#if __GNUC__ >= 2 && defined(__ELF__)
# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
/*
* Cairo uses the following function attributes in order to improve the
* generated code (effectively by manual inter-procedural analysis).
*
* 'cairo_pure': The function is only allowed to read from its arguments
* and global memory (i.e. following a pointer argument or
* accessing a shared variable). The return value should
* only depend on its arguments, and for an identical set of
* arguments should return the same value.
*
* 'cairo_const': The function is only allowed to read from its arguments.
* It is not allowed to access global memory. The return
* value should only depend its arguments, and for an
* identical set of arguments should return the same value.
* This is currently the most strict function attribute.
*
* Both these function attributes allow gcc to perform CSE and
* constant-folding, with 'cairo_const 'also guaranteeing that pointer contents
* do not change across the function call.
*/
#if __GNUC__ >= 3
#define cairo_pure __attribute__((pure))
#define cairo_const __attribute__((const))
#else
#define cairo_pure
#define cairo_const
#endif
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
#endif
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#define popen _popen
#endif
#ifdef _MSC_VER
#undef inline
#define inline __inline
#endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
#endif

View file

@ -0,0 +1,75 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
/**
* cairo_debug_reset_static_data:
*
* Resets all static data within cairo to its original state,
* (ie. identical to the state at the time of program invocation). For
* example, all caches within cairo will be flushed empty.
*
* This function is intended to be useful when using memory-checking
* tools such as valgrind. When valgrind's memcheck analyzes a
* cairo-using program without a call to cairo_debug_reset_static_data(),
* it will report all data reachable via cairo's static objects as
* "still reachable". Calling cairo_debug_reset_static_data() just prior
* to program termination will make it easier to get squeaky clean
* reports from valgrind.
*
* WARNING: It is only safe to call this function when there are no
* active cairo objects remaining, (ie. the appropriate destroy
* functions have been called as necessary). If there are active cairo
* objects, this call is likely to cause a crash, (eg. an assertion
* failure due to a hash table being destroyed when non-empty).
**/
void
cairo_debug_reset_static_data (void)
{
CAIRO_MUTEX_INITIALIZE ();
_cairo_font_face_reset_static_data ();
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
_cairo_scaled_font_reset_static_data ();
_cairo_pattern_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}

View file

@ -0,0 +1,149 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Adrian Johnson.
*
* Author(s):
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
#include "cairo-output-stream-private.h"
#include <zlib.h>
#define BUFFER_SIZE 16384
typedef struct _cairo_deflate_stream {
cairo_output_stream_t base;
cairo_output_stream_t *output;
z_stream zlib_stream;
unsigned char input_buf[BUFFER_SIZE];
unsigned char output_buf[BUFFER_SIZE];
} cairo_deflate_stream_t;
static void
cairo_deflate_stream_deflate (cairo_deflate_stream_t *stream, cairo_bool_t flush)
{
int ret;
cairo_bool_t finished;
do {
ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH);
if (flush || stream->zlib_stream.avail_out == 0)
{
_cairo_output_stream_write (stream->output,
stream->output_buf,
BUFFER_SIZE - stream->zlib_stream.avail_out);
stream->zlib_stream.next_out = stream->output_buf;
stream->zlib_stream.avail_out = BUFFER_SIZE;
}
finished = TRUE;
if (stream->zlib_stream.avail_in != 0)
finished = FALSE;
if (flush && ret != Z_STREAM_END)
finished = FALSE;
} while (!finished);
stream->zlib_stream.next_in = stream->input_buf;
}
static cairo_status_t
_cairo_deflate_stream_write (cairo_output_stream_t *base,
const unsigned char *data,
unsigned int length)
{
cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
unsigned int count;
const unsigned char *p = data;
while (length) {
count = length;
if (count > BUFFER_SIZE - stream->zlib_stream.avail_in)
count = BUFFER_SIZE - stream->zlib_stream.avail_in;
memcpy (stream->input_buf + stream->zlib_stream.avail_in, p, count);
p += count;
stream->zlib_stream.avail_in += count;
length -= count;
if (stream->zlib_stream.avail_in == BUFFER_SIZE)
cairo_deflate_stream_deflate (stream, FALSE);
}
return _cairo_output_stream_get_status (stream->output);
}
static cairo_status_t
_cairo_deflate_stream_close (cairo_output_stream_t *base)
{
cairo_deflate_stream_t *stream = (cairo_deflate_stream_t *) base;
cairo_deflate_stream_deflate (stream, TRUE);
deflateEnd (&stream->zlib_stream);
return _cairo_output_stream_get_status (stream->output);
}
cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output)
{
cairo_deflate_stream_t *stream;
if (output->status)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_deflate_stream_t));
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_deflate_stream_write,
_cairo_deflate_stream_close);
stream->output = output;
stream->zlib_stream.zalloc = Z_NULL;
stream->zlib_stream.zfree = Z_NULL;
stream->zlib_stream.opaque = Z_NULL;
if (deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
free (stream);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
stream->zlib_stream.next_in = stream->input_buf;
stream->zlib_stream.avail_in = 0;
stream->zlib_stream.next_out = stream->output_buf;
stream->zlib_stream.avail_out = BUFFER_SIZE;
return &stream->base;
}

View file

@ -0,0 +1,138 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_DEPRECATED_H
#define CAIRO_DEPRECATED_H
/* The %CAIRO_FORMAT_RGB16_565 value was added in cairo 1.2.0 as part
* of fixing cairo's xlib backend to work with X servers advertising a
* 16-bit, 565 visual. But as it turned out, adding this format to
* #cairo_format_t was not necessary, and was a mistake, (cairo's xlib
* backend can work fine with 16-bit visuals in the same way it works
* with BGR visuals without any BGR formats in
* #cairo_format_t).
*
* Additionally, the support for the RGB16_565 format was never
* completely implemented. So while this format value is currently
* deprecated, it may eventually acquire complete support in the future.
*/
#define CAIRO_FORMAT_RGB16_565 4
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
* having to dig through lots of documentation.
*
* The first set of REPLACED_BY functions is for functions whose names
* have just been changed. So fixing these up is mechanical, (and
* automated by means of the cairo/util/cairo-api-update script.
*
* The second set of DEPRECATED_BY functions is for functions where
* the replacement is used in a different way, (ie. different
* arguments, multiple functions instead of one, etc). Fixing these up
* will require a bit more work on the user's part, (and hopefully we
* can get cairo-api-update to find these and print some guiding
* information).
*/
#define cairo_current_font_extents cairo_current_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_get_font_extents cairo_get_font_extents_REPLACED_BY_cairo_font_extents
#define cairo_current_operator cairo_current_operator_REPLACED_BY_cairo_get_operator
#define cairo_current_tolerance cairo_current_tolerance_REPLACED_BY_cairo_get_tolerance
#define cairo_current_point cairo_current_point_REPLACED_BY_cairo_get_current_point
#define cairo_current_fill_rule cairo_current_fill_rule_REPLACED_BY_cairo_get_fill_rule
#define cairo_current_line_width cairo_current_line_width_REPLACED_BY_cairo_get_line_width
#define cairo_current_line_cap cairo_current_line_cap_REPLACED_BY_cairo_get_line_cap
#define cairo_current_line_join cairo_current_line_join_REPLACED_BY_cairo_get_line_join
#define cairo_current_miter_limit cairo_current_miter_limit_REPLACED_BY_cairo_get_miter_limit
#define cairo_current_matrix cairo_current_matrix_REPLACED_BY_cairo_get_matrix
#define cairo_current_target_surface cairo_current_target_surface_REPLACED_BY_cairo_get_target
#define cairo_get_status cairo_get_status_REPLACED_BY_cairo_status
#define cairo_concat_matrix cairo_concat_matrix_REPLACED_BY_cairo_transform
#define cairo_scale_font cairo_scale_font_REPLACED_BY_cairo_set_font_size
#define cairo_select_font cairo_select_font_REPLACED_BY_cairo_select_font_face
#define cairo_transform_font cairo_transform_font_REPLACED_BY_cairo_set_font_matrix
#define cairo_transform_point cairo_transform_point_REPLACED_BY_cairo_user_to_device
#define cairo_transform_distance cairo_transform_distance_REPLACED_BY_cairo_user_to_device_distance
#define cairo_inverse_transform_point cairo_inverse_transform_point_REPLACED_BY_cairo_device_to_user
#define cairo_inverse_transform_distance cairo_inverse_transform_distance_REPLACED_BY_cairo_device_to_user_distance
#define cairo_init_clip cairo_init_clip_REPLACED_BY_cairo_reset_clip
#define cairo_surface_create_for_image cairo_surface_create_for_image_REPLACED_BY_cairo_image_surface_create_for_data
#define cairo_default_matrix cairo_default_matrix_REPLACED_BY_cairo_identity_matrix
#define cairo_matrix_set_affine cairo_matrix_set_affine_REPLACED_BY_cairo_matrix_init
#define cairo_matrix_set_identity cairo_matrix_set_identity_REPLACED_BY_cairo_matrix_init_identity
#define cairo_pattern_add_color_stop cairo_pattern_add_color_stop_REPLACED_BY_cairo_pattern_add_color_stop_rgba
#define cairo_set_rgb_color cairo_set_rgb_color_REPLACED_BY_cairo_set_source_rgb
#define cairo_set_pattern cairo_set_pattern_REPLACED_BY_cairo_set_source
#define cairo_xlib_surface_create_for_pixmap_with_visual cairo_xlib_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xlib_surface_create_for_window_with_visual cairo_xlib_surface_create_for_window_with_visual_REPLACED_BY_cairo_xlib_surface_create
#define cairo_xcb_surface_create_for_pixmap_with_visual cairo_xcb_surface_create_for_pixmap_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_xcb_surface_create_for_window_with_visual cairo_xcb_surface_create_for_window_with_visual_REPLACED_BY_cairo_xcb_surface_create
#define cairo_ps_surface_set_dpi cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_pdf_surface_set_dpi cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_svg_surface_set_dpi cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_atsui_font_face_create_for_atsu_font_id cairo_atsui_font_face_create_for_atsu_font_id_REPLACED_BY_cairo_quartz_font_face_create_for_atsu_font_id
#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
#define cairo_get_path_flat cairo_get_path_flat_DEPRECATED_BY_cairo_get_path_flat
#define cairo_set_alpha cairo_set_alpha_DEPRECATED_BY_cairo_set_source_rgba_OR_cairo_paint_with_alpha
#define cairo_show_surface cairo_show_surface_DEPRECATED_BY_cairo_set_source_surface_AND_cairo_paint
#define cairo_copy cairo_copy_DEPRECATED_BY_cairo_create_AND_MANY_INDIVIDUAL_FUNCTIONS
#define cairo_surface_set_repeat cairo_surface_set_repeat_DEPRECATED_BY_cairo_pattern_set_extend
#define cairo_surface_set_matrix cairo_surface_set_matrix_DEPRECATED_BY_cairo_pattern_set_matrix
#define cairo_surface_get_matrix cairo_surface_get_matrix_DEPRECATED_BY_cairo_pattern_get_matrix
#define cairo_surface_set_filter cairo_surface_set_filter_DEPRECATED_BY_cairo_pattern_set_filter
#define cairo_surface_get_filter cairo_surface_get_filter_DEPRECATED_BY_cairo_pattern_get_filter
#define cairo_matrix_create cairo_matrix_create_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_destroy cairo_matrix_destroy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_copy cairo_matrix_copy_DEPRECATED_BY_cairo_matrix_t
#define cairo_matrix_get_affine cairo_matrix_get_affine_DEPRECATED_BY_cairo_matrix_t
#define cairo_set_target_surface cairo_set_target_surface_DEPRECATED_BY_cairo_create
#define cairo_set_target_glitz cairo_set_target_glitz_DEPRECATED_BY_cairo_glitz_surface_create
#define cairo_set_target_image cairo_set_target_image_DEPRECATED_BY_cairo_image_surface_create_for_data
#define cairo_set_target_pdf cairo_set_target_pdf_DEPRECATED_BY_cairo_pdf_surface_create
#define cairo_set_target_png cairo_set_target_png_DEPRECATED_BY_cairo_surface_write_to_png
#define cairo_set_target_ps cairo_set_target_ps_DEPRECATED_BY_cairo_ps_surface_create
#define cairo_set_target_quartz cairo_set_target_quartz_DEPRECATED_BY_cairo_quartz_surface_create
#define cairo_set_target_win32 cairo_set_target_win32_DEPRECATED_BY_cairo_win32_surface_create
#define cairo_set_target_xcb cairo_set_target_xcb_DEPRECATED_BY_cairo_xcb_surface_create
#define cairo_set_target_drawable cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#endif /* CAIRO_DEPRECATED_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,67 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@isi.edu>
*/
/*
* Environment variables affecting the backend:
*
* %CAIRO_DIRECTFB_NO_ACCEL (boolean)
* if found, disables acceleration at all
*
* %CAIRO_DIRECTFB_ARGB_FONT (boolean)
* if found, enables using ARGB fonts instead of A8
*/
#ifndef CAIRO_DIRECTFB_H
#define CAIRO_DIRECTFB_H
#include "cairo.h"
#if CAIRO_HAS_DIRECTFB_SURFACE
#include <directfb.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *surface);
CAIRO_END_DECLS
#else /*CAIRO_HAS_DIRECTFB_SURFACE*/
# error Cairo was not compiled with support for the directfb backend
#endif /*CAIRO_HAS_DIRECTFB_SURFACE*/
#endif /*CAIRO_DIRECTFB_H*/

View file

@ -0,0 +1,28 @@
/* Generated by configure. Do not edit. */
#ifndef CAIRO_FEATURES_H
#define CAIRO_FEATURES_H
#define CAIRO_HAS_IMAGE_SURFACE 1
#define CAIRO_HAS_PDF_SURFACE 1
#define CAIRO_HAS_PNG_FUNCTIONS 1
//#define CAIRO_HAS_PS_SURFACE 1
#define CAIRO_HAS_SVG_SURFACE 1
//#define CAIRO_HAS_USER_FONT 1
/*#undef CAIRO_HAS_QUARTZ_FONT */
/*#undef CAIRO_HAS_QUARTZ_SURFACE */
#ifndef cairo_public
#define cairo_public
#endif
#ifdef flagWIN32
#define CAIRO_HAS_WIN32_SURFACE 1
#define CAIRO_HAS_WIN32_FONT 1
#else
#define CAIRO_HAS_XLIB_SURFACE 1
#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1
#define CAIRO_HAS_FT_FONT 1
#endif
#endif

View file

@ -0,0 +1,244 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
#ifndef CAIRO_FIXED_PRIVATE_H
#define CAIRO_FIXED_PRIVATE_H
#include "cairo-fixed-type-private.h"
#include "cairo-wideint-private.h"
/* Implementation */
#if (CAIRO_FIXED_BITS != 32)
# error CAIRO_FIXED_BITS must be 32, and the type must be a 32-bit type.
# error To remove this limitation, you will have to fix the tesselator.
#endif
#define CAIRO_FIXED_ONE ((cairo_fixed_t)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_ONE_DOUBLE ((double)(1 << CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_EPSILON ((cairo_fixed_t)(1))
#define CAIRO_FIXED_FRAC_MASK (((cairo_fixed_unsigned_t)(-1)) >> (CAIRO_FIXED_BITS - CAIRO_FIXED_FRAC_BITS))
#define CAIRO_FIXED_WHOLE_MASK (~CAIRO_FIXED_FRAC_MASK)
static inline cairo_fixed_t
_cairo_fixed_from_int (int i)
{
return i << CAIRO_FIXED_FRAC_BITS;
}
/* This is the "magic number" approach to converting a double into fixed
* point as described here:
*
* http://www.stereopsis.com/sree/fpu2006.html (an overview)
* http://www.d6.com/users/checker/pdfs/gdmfp.pdf (in detail)
*
* The basic idea is to add a large enough number to the double that the
* literal floating point is moved up to the extent that it forces the
* double's value to be shifted down to the bottom of the mantissa (to make
* room for the large number being added in). Since the mantissa is, at a
* given moment in time, a fixed point integer itself, one can convert a
* float to various fixed point representations by moving around the point
* of a floating point number through arithmetic operations. This behavior
* is reliable on most modern platforms as it is mandated by the IEEE-754
* standard for floating point arithmetic.
*
* For our purposes, a "magic number" must be carefully selected that is
* both large enough to produce the desired point-shifting effect, and also
* has no lower bits in its representation that would interfere with our
* value at the bottom of the mantissa. The magic number is calculated as
* follows:
*
* (2 ^ (MANTISSA_SIZE - FRACTIONAL_SIZE)) * 1.5
*
* where in our case:
* - MANTISSA_SIZE for 64-bit doubles is 52
* - FRACTIONAL_SIZE for 16.16 fixed point is 16
*
* Although this approach provides a very large speedup of this function
* on a wide-array of systems, it does come with two caveats:
*
* 1) It uses banker's rounding as opposed to arithmetic rounding.
* 2) It doesn't function properly if the FPU is in single-precision
* mode.
*/
/* The 16.16 number must always be available */
#define CAIRO_MAGIC_NUMBER_FIXED_16_16 (103079215104.0)
#if CAIRO_FIXED_BITS <= 32
#define CAIRO_MAGIC_NUMBER_FIXED ((1LL << (52 - CAIRO_FIXED_FRAC_BITS)) * 1.5)
/* For 32-bit fixed point numbers */
static inline cairo_fixed_t
_cairo_fixed_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
u.d = d + CAIRO_MAGIC_NUMBER_FIXED;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
#else
# error Please define a magic number for your fixed point type!
# error See cairo-fixed-private.h for details.
#endif
static inline cairo_fixed_t
_cairo_fixed_from_26_6 (uint32_t i)
{
#if CAIRO_FIXED_FRAC_BITS > 6
return i << (CAIRO_FIXED_FRAC_BITS - 6);
#else
return i >> (6 - CAIRO_FIXED_FRAC_BITS);
#endif
}
static inline double
_cairo_fixed_to_double (cairo_fixed_t f)
{
return ((double) f) / CAIRO_FIXED_ONE_DOUBLE;
}
static inline int
_cairo_fixed_is_integer (cairo_fixed_t f)
{
return (f & CAIRO_FIXED_FRAC_MASK) == 0;
}
static inline int
_cairo_fixed_integer_part (cairo_fixed_t f)
{
return f >> CAIRO_FIXED_FRAC_BITS;
}
static inline int
_cairo_fixed_integer_floor (cairo_fixed_t f)
{
if (f >= 0)
return f >> CAIRO_FIXED_FRAC_BITS;
else
return -((-f - 1) >> CAIRO_FIXED_FRAC_BITS) - 1;
}
static inline int
_cairo_fixed_integer_ceil (cairo_fixed_t f)
{
if (f > 0)
return ((f - 1)>>CAIRO_FIXED_FRAC_BITS) + 1;
else
return - (-f >> CAIRO_FIXED_FRAC_BITS);
}
/* A bunch of explicit 16.16 operators; we need these
* to interface with pixman and other backends that require
* 16.16 fixed point types.
*/
static inline cairo_fixed_16_16_t
_cairo_fixed_to_16_16 (cairo_fixed_t f)
{
#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
return f;
#elif CAIRO_FIXED_FRAC_BITS > 16
/* We're just dropping the low bits, so we won't ever got over/underflow here */
return f >> (CAIRO_FIXED_FRAC_BITS - 16);
#else
cairo_fixed_16_16_t x;
/* Handle overflow/underflow by clamping to the lowest/highest
* value representable as 16.16
*/
if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
x = INT32_MIN;
} else if ((f >> CAIRO_FIXED_FRAC_BITS) > INT16_MAX) {
x = INT32_MAX;
} else {
x = f << (16 - CAIRO_FIXED_FRAC_BITS);
}
return x;
#endif
}
static inline cairo_fixed_16_16_t
_cairo_fixed_16_16_from_double (double d)
{
union {
double d;
int32_t i[2];
} u;
u.d = d + CAIRO_MAGIC_NUMBER_FIXED_16_16;
#ifdef FLOAT_WORDS_BIGENDIAN
return u.i[1];
#else
return u.i[0];
#endif
}
#if CAIRO_FIXED_BITS == 32
static inline cairo_fixed_t
_cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
{
cairo_int64_t temp = _cairo_int32x32_64_mul (a, b);
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes a * b / c */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
return _cairo_int64_to_int32(quo);
}
#else
# error Please define multiplication and other operands for your fixed-point type size
#endif
#endif /* CAIRO_FIXED_PRIVATE_H */

View file

@ -0,0 +1,70 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
#ifndef CAIRO_FIXED_TYPE_PRIVATE_H
#define CAIRO_FIXED_TYPE_PRIVATE_H
#include "cairo-wideint-type-private.h"
/*
* Fixed-point configuration
*/
typedef int32_t cairo_fixed_16_16_t;
typedef cairo_int64_t cairo_fixed_32_32_t;
typedef cairo_int64_t cairo_fixed_48_16_t;
typedef cairo_int128_t cairo_fixed_64_64_t;
typedef cairo_int128_t cairo_fixed_96_32_t;
/* Eventually, we should allow changing this, but I think
* there are some assumptions in the tesselator about the
* size of a fixed type. For now, it must be 32.
*/
#define CAIRO_FIXED_BITS 32
/* The number of fractional bits. Changing this involves
* making sure that you compute a double-to-fixed magic number.
* (see below).
*/
#define CAIRO_FIXED_FRAC_BITS 8
/* A signed type %CAIRO_FIXED_BITS in size; the main fixed point type */
typedef int32_t cairo_fixed_t;
/* An unsigned type of the same size as #cairo_fixed_t */
typedef uint32_t cairo_fixed_unsigned_t;
#endif /* CAIRO_FIXED_TYPE_PRIVATE_H */

View file

@ -0,0 +1,39 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-fixed-private.h"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,209 @@
/*
* Copyright © 2004 Keith Packard
* Copyright © 2008 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Keith Packard
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Behdad Esfahbod <behdad@behdad.org>
*/
#include "cairoint.h"
/*
* This file implements a user-font rendering the decendant of the Hershey
* font coded by Keith Packard for use in the Twin window system.
* The actual font data is in cairo-font-face-twin-data.c
*
* Ported to cairo user font by Behdad Esfahbod.
*/
#define twin_glyph_left(g) ((g)[0])
#define twin_glyph_right(g) ((g)[1])
#define twin_glyph_ascent(g) ((g)[2])
#define twin_glyph_descent(g) ((g)[3])
#define twin_glyph_n_snap_x(g) ((g)[4])
#define twin_glyph_n_snap_y(g) ((g)[5])
#define twin_glyph_snap_x(g) (&g[6])
#define twin_glyph_snap_y(g) (twin_glyph_snap_x(g) + twin_glyph_n_snap_x(g))
#define twin_glyph_draw(g) (twin_glyph_snap_y(g) + twin_glyph_n_snap_y(g))
#define SNAPI(p) (p)
#define SNAPH(p) (p)
#define FX(g) ((g) / 64.)
#define FY(g) ((g) / 64.)
static cairo_status_t
twin_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_t *cr,
cairo_font_extents_t *metrics)
{
metrics->ascent = FY (50);
metrics->descent = FY (14);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
twin_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font,
unsigned long unicode,
unsigned long *glyph)
{
/* We use an identity charmap. Which means we could live
* with no unicode_to_glyph method too. But we define this
* to map all unknown chars to a single unknown glyph to
* reduce pressure on cache. */
if (unicode < ARRAY_LENGTH (_cairo_twin_charmap))
*glyph = unicode;
else
*glyph = 0;
return CAIRO_STATUS_SUCCESS;
}
#define SNAPX(p) _twin_snap (p, info.snap_x, info.n_snap_x)
#define SNAPY(p) _twin_snap (p, info.snap_y, info.n_snap_y)
static double
_twin_snap (double v, int a, int b)
{
return v; /* XXX */
}
static cairo_status_t
twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *metrics)
{
double x1, y1, x2, y2, x3, y3;
const int8_t *b = _cairo_twin_outlines +
_cairo_twin_charmap[glyph >= ARRAY_LENGTH (_cairo_twin_charmap) ? 0 : glyph];
const int8_t *g = twin_glyph_draw(b);
struct {
cairo_bool_t snap;
int snap_x;
int snap_y;
int n_snap_x;
int n_snap_y;
} info = {FALSE};
cairo_set_line_width (cr, 0.06);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
for (;;) {
switch (*g++) {
case 'M':
cairo_close_path (cr);
/* fall through */
case 'm':
x1 = FX(*g++);
y1 = FY(*g++);
if (info.snap)
{
x1 = SNAPX (x1);
y1 = SNAPY (y1);
}
cairo_move_to (cr, x1, y1);
continue;
case 'L':
cairo_close_path (cr);
/* fall through */
case 'l':
x1 = FX(*g++);
y1 = FY(*g++);
if (info.snap)
{
x1 = SNAPX (x1);
y1 = SNAPY (y1);
}
cairo_line_to (cr, x1, y1);
continue;
case 'C':
cairo_close_path (cr);
/* fall through */
case 'c':
x1 = FX(*g++);
y1 = FY(*g++);
x2 = FX(*g++);
y2 = FY(*g++);
x3 = FX(*g++);
y3 = FY(*g++);
if (info.snap)
{
x1 = SNAPX (x1);
y1 = SNAPY (y1);
x2 = SNAPX (x2);
y2 = SNAPY (y2);
x3 = SNAPX (x3);
y3 = SNAPY (y3);
}
cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
continue;
case 'E':
cairo_close_path (cr);
/* fall through */
case 'e':
cairo_stroke (cr);
break;
case 'X':
/* filler */
continue;
}
break;
}
metrics->x_advance = FX(twin_glyph_right(b)) + cairo_get_line_width (cr);
metrics->x_advance += cairo_get_line_width (cr)/* XXX 2*x.margin */;
if (info.snap)
metrics->x_advance = SNAPI (SNAPX (metrics->x_advance));
return CAIRO_STATUS_SUCCESS;
}
cairo_font_face_t *
_cairo_font_face_twin_create (cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
cairo_font_face_t *twin_font_face;
twin_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (twin_font_face, twin_scaled_font_init);
cairo_user_font_face_set_render_glyph_func (twin_font_face, twin_scaled_font_render_glyph);
cairo_user_font_face_set_unicode_to_glyph_func (twin_font_face, twin_scaled_font_unicode_to_glyph);
return twin_font_face;
}

View file

@ -0,0 +1,776 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#define _BSD_SOURCE /* for strdup() */
#include "cairoint.h"
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
/* #cairo_font_face_t */
const cairo_toy_font_face_t _cairo_font_face_nil = {
{
{ 0 }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
},
CAIRO_FONT_FAMILY_DEFAULT, /* family */
TRUE, /* owns_family */
CAIRO_FONT_SLANT_DEFAULT, /* slant */
CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
static const cairo_toy_font_face_t _cairo_font_face_null_pointer = {
{
{ 0 }, /* hash_entry */
CAIRO_STATUS_NULL_POINTER, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
},
CAIRO_FONT_FAMILY_DEFAULT, /* family */
TRUE, /* owns_family */
CAIRO_FONT_SLANT_DEFAULT, /* slant */
CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
static const cairo_toy_font_face_t _cairo_font_face_invalid_string = {
{
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_STRING, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
},
CAIRO_FONT_FAMILY_DEFAULT, /* family */
TRUE, /* owns_family */
CAIRO_FONT_SLANT_DEFAULT, /* slant */
CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
static const cairo_toy_font_face_t _cairo_font_face_invalid_slant = {
{
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_SLANT, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
},
CAIRO_FONT_FAMILY_DEFAULT, /* family */
TRUE, /* owns_family */
CAIRO_FONT_SLANT_DEFAULT, /* slant */
CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
static const cairo_toy_font_face_t _cairo_font_face_invalid_weight = {
{
{ 0 }, /* hash_entry */
CAIRO_STATUS_INVALID_WEIGHT, /* status */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend
},
CAIRO_FONT_FAMILY_DEFAULT, /* family */
TRUE, /* owns_family */
CAIRO_FONT_SLANT_DEFAULT, /* slant */
CAIRO_FONT_WEIGHT_DEFAULT /* weight */
};
cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&font_face->status, status);
return _cairo_error (status);
}
void
_cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend)
{
CAIRO_MUTEX_INITIALIZE ();
font_face->status = CAIRO_STATUS_SUCCESS;
CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
font_face->backend = backend;
_cairo_user_data_array_init (&font_face->user_data);
}
/**
* cairo_font_face_reference:
* @font_face: a #cairo_font_face_t, (may be %NULL in which case this
* function does nothing).
*
* Increases the reference count on @font_face by one. This prevents
* @font_face from being destroyed until a matching call to
* cairo_font_face_destroy() is made.
*
* The number of references to a #cairo_font_face_t can be get using
* cairo_font_face_get_reference_count().
*
* Return value: the referenced #cairo_font_face_t.
**/
cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face;
/* We would normally assert that we have a reference here but we
* can't get away with that due to the zombie case as documented
* in _cairo_ft_font_face_destroy. */
_cairo_reference_count_inc (&font_face->ref_count);
return font_face;
}
slim_hidden_def (cairo_font_face_reference);
/**
* cairo_font_face_destroy:
* @font_face: a #cairo_font_face_t
*
* Decreases the reference count on @font_face by one. If the result
* is zero, then @font_face and all associated resources are freed.
* See cairo_font_face_reference().
**/
void
cairo_font_face_destroy (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
return;
if (font_face->backend->destroy)
font_face->backend->destroy (font_face);
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
* need to effectively mutually reference each other
*/
if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
return;
_cairo_user_data_array_fini (&font_face->user_data);
free (font_face);
}
slim_hidden_def (cairo_font_face_destroy);
/**
* cairo_font_face_get_type:
* @font_face: a font face
*
* This function returns the type of the backend used to create
* a font face. See #cairo_font_type_t for available types.
*
* Return value: The type of @font_face.
*
* Since: 1.2
**/
cairo_font_type_t
cairo_font_face_get_type (cairo_font_face_t *font_face)
{
return font_face->backend->type;
}
/**
* cairo_font_face_get_reference_count:
* @font_face: a #cairo_font_face_t
*
* Returns the current reference count of @font_face.
*
* Return value: the current reference count of @font_face. If the
* object is a nil object, 0 will be returned.
*
* Since: 1.4
**/
unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
{
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return 0;
return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
}
/**
* cairo_font_face_status:
* @font_face: a #cairo_font_face_t
*
* Checks whether an error has previously occurred for this
* font face
*
* Return value: %CAIRO_STATUS_SUCCESS or another error such as
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face)
{
return font_face->status;
}
/**
* cairo_font_face_get_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of the #cairo_user_data_key_t the user data was
* attached to
*
* Return user data previously attached to @font_face using the specified
* key. If no user data has been attached with the given key this
* function returns %NULL.
*
* Return value: the user data previously attached or %NULL.
**/
void *
cairo_font_face_get_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key)
{
return _cairo_user_data_array_get_data (&font_face->user_data,
key);
}
slim_hidden_def (cairo_font_face_get_user_data);
/**
* cairo_font_face_set_user_data:
* @font_face: a #cairo_font_face_t
* @key: the address of a #cairo_user_data_key_t to attach the user data to
* @user_data: the user data to attach to the font face
* @destroy: a #cairo_destroy_func_t which will be called when the
* font face is destroyed or when new user data is attached using the
* same key.
*
* Attach user data to @font_face. To remove user data from a font face,
* call this function with the key that was used to set it and %NULL
* for @data.
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
* slot could not be allocated for the user data.
**/
cairo_status_t
cairo_font_face_set_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy)
{
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face->status;
return _cairo_user_data_array_set_data (&font_face->user_data,
key, user_data, destroy);
}
slim_hidden_def (cairo_font_face_set_user_data);
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
static int
_cairo_toy_font_face_keys_equal (const void *key_a,
const void *key_b);
/* We maintain a hash table from family/weight/slant =>
* #cairo_font_face_t for #cairo_toy_font_t. The primary purpose of
* this mapping is to provide unique #cairo_font_face_t values so that
* our cache and mapping from #cairo_font_face_t => #cairo_scaled_font_t
* works. Once the corresponding #cairo_font_face_t objects fall out of
* downstream caches, we don't need them in this hash table anymore.
*
* Modifications to this hash table are protected by
* _cairo_font_face_mutex.
*/
static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL;
static cairo_hash_table_t *
_cairo_toy_font_face_hash_table_lock (void)
{
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
if (cairo_toy_font_face_hash_table == NULL)
{
cairo_toy_font_face_hash_table =
_cairo_hash_table_create (_cairo_toy_font_face_keys_equal);
if (cairo_toy_font_face_hash_table == NULL) {
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return NULL;
}
}
return cairo_toy_font_face_hash_table;
}
static void
_cairo_toy_font_face_hash_table_unlock (void)
{
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
}
/**
* _cairo_toy_font_face_init_key:
*
* Initialize those portions of #cairo_toy_font_face_t needed to use
* it as a hash table key, including the hash code buried away in
* font_face->base.hash_entry. No memory allocation is performed here
* so that no fini call is needed. We do this to make it easier to use
* an automatic #cairo_toy_font_face_t variable as a key.
**/
static void
_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
unsigned long hash;
key->family = family;
key->owns_family = FALSE;
key->slant = slant;
key->weight = weight;
/* 1607 and 1451 are just a couple of arbitrary primes. */
hash = _cairo_hash_string (family);
hash += ((unsigned long) slant) * 1607;
hash += ((unsigned long) weight) * 1451;
assert (hash != 0);
key->base.hash_entry.hash = hash;
}
static cairo_status_t
_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
char *family_copy;
family_copy = strdup (family);
if (family_copy == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_toy_font_face_init_key (font_face, family_copy,
slant, weight);
font_face->owns_family = TRUE;
_cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
{
/* We assert here that we own font_face->family before casting
* away the const qualifer. */
assert (font_face->owns_family);
free ((char*) font_face->family);
}
static int
_cairo_toy_font_face_keys_equal (const void *key_a,
const void *key_b)
{
const cairo_toy_font_face_t *face_a = key_a;
const cairo_toy_font_face_t *face_b = key_b;
return (strcmp (face_a->family, face_b->family) == 0 &&
face_a->slant == face_b->slant &&
face_a->weight == face_b->weight);
}
/**
* cairo_toy_font_face_create:
* @family: a font family name, encoded in UTF-8
* @slant: the slant for the font
* @weight: the weight for the font
*
* Creates a font face from a triplet of family, slant, and weight.
* These font faces are used in implementation of the the #cairo_t "toy"
* font API.
*
* If @family is the zero-length string "", the platform-specific default
* family is assumed. The default family then can be queried using
* cairo_toy_font_face_get_family().
*
* The cairo_select_font_face() function uses this to create font faces.
* See that function for limitations of toy font faces.
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.8
**/
cairo_font_face_t *
cairo_toy_font_face_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
cairo_status_t status;
cairo_toy_font_face_t key, *font_face;
cairo_hash_table_t *hash_table;
if (family == NULL)
return (cairo_font_face_t*) &_cairo_font_face_null_pointer;
/* Make sure we've got valid UTF-8 for the family */
status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
if (status == CAIRO_STATUS_INVALID_STRING)
return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
else if (status)
return (cairo_font_face_t*) &_cairo_font_face_nil;
switch (slant) {
case CAIRO_FONT_SLANT_NORMAL:
case CAIRO_FONT_SLANT_ITALIC:
case CAIRO_FONT_SLANT_OBLIQUE:
break;
default:
return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
}
switch (weight) {
case CAIRO_FONT_WEIGHT_NORMAL:
case CAIRO_FONT_WEIGHT_BOLD:
break;
default:
return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
}
if (*family == '\0')
family = CAIRO_FONT_FAMILY_DEFAULT;
hash_table = _cairo_toy_font_face_hash_table_lock ();
if (hash_table == NULL)
goto UNWIND;
_cairo_toy_font_face_init_key (&key, family, slant, weight);
/* Return existing font_face if it exists in the hash table. */
if (_cairo_hash_table_lookup (hash_table,
&key.base.hash_entry,
(cairo_hash_entry_t **) &font_face))
{
if (! font_face->base.status) {
/* We increment the reference count here manually to avoid
double-locking. */
_cairo_reference_count_inc (&font_face->base.ref_count);
_cairo_toy_font_face_hash_table_unlock ();
return &font_face->base;
}
/* remove the bad font from the hash table */
_cairo_hash_table_remove (hash_table, &key.base.hash_entry);
font_face->base.hash_entry.hash = 0;
}
/* Otherwise create it and insert into hash table. */
font_face = malloc (sizeof (cairo_toy_font_face_t));
if (font_face == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_HASH_TABLE_LOCK;
}
status = _cairo_toy_font_face_init (font_face, family, slant, weight);
if (status)
goto UNWIND_FONT_FACE_MALLOC;
status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
if (status)
goto UNWIND_FONT_FACE_INIT;
_cairo_toy_font_face_hash_table_unlock ();
return &font_face->base;
UNWIND_FONT_FACE_INIT:
_cairo_toy_font_face_fini (font_face);
UNWIND_FONT_FACE_MALLOC:
free (font_face);
UNWIND_HASH_TABLE_LOCK:
_cairo_toy_font_face_hash_table_unlock ();
UNWIND:
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
slim_hidden_def (cairo_toy_font_face_create);
static void
_cairo_toy_font_face_destroy (void *abstract_face)
{
cairo_toy_font_face_t *font_face = abstract_face;
cairo_hash_table_t *hash_table;
if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->base.ref_count))
return;
hash_table = _cairo_toy_font_face_hash_table_lock ();
/* All created objects must have been mapped in the hash table. */
assert (hash_table != NULL);
if (font_face->base.hash_entry.hash != 0)
_cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
_cairo_toy_font_face_hash_table_unlock ();
_cairo_toy_font_face_fini (font_face);
}
static cairo_status_t
_cairo_toy_font_face_scaled_font_get_implementation (void *abstract_font_face,
cairo_font_face_t **font_face_out)
{
cairo_toy_font_face_t *font_face = abstract_font_face;
cairo_status_t status;
if (font_face->base.status)
return font_face->base.status;
if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend)
{
const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
if (backend->get_implementation == NULL) {
*font_face_out = &font_face->base;
return CAIRO_STATUS_SUCCESS;
}
status = backend->get_implementation (font_face,
font_face_out);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_font_face_set_error (&font_face->base, status);
}
status = _cairo_user_scaled_font_backend.get_implementation (font_face,
font_face_out);
return _cairo_font_face_set_error (&font_face->base, status);
}
static cairo_status_t
_cairo_toy_font_face_scaled_font_create (void *abstract_font_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **scaled_font)
{
cairo_toy_font_face_t *font_face = abstract_font_face;
cairo_status_t status;
if (font_face->base.status)
return font_face->base.status;
status = cairo_font_options_status ((cairo_font_options_t *) options);
if (status)
return status;
if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend)
{
const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
*scaled_font = NULL;
status = backend->create_toy (font_face,
font_matrix,
ctm,
options,
scaled_font);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_font_face_set_error (&font_face->base, status);
if (*scaled_font)
cairo_scaled_font_destroy (*scaled_font);
}
status = _cairo_user_scaled_font_backend.create_toy (font_face,
font_matrix,
ctm,
options,
scaled_font);
return _cairo_font_face_set_error (&font_face->base, status);
}
static cairo_bool_t
_cairo_font_face_is_toy (cairo_font_face_t *font_face)
{
return font_face->backend == &_cairo_toy_font_face_backend;
}
/**
* cairo_toy_font_face_get_family:
* @font_face: A toy font face
*
* Gets the familly name of a toy font.
*
* Return value: The family name. This string is owned by the font face
* and remains valid as long as the font face is alive (referenced).
*
* Since: 1.8
**/
const char *
cairo_toy_font_face_get_family (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_FAMILY_DEFAULT;
}
assert (toy_font_face->owns_family);
return toy_font_face->family;
}
/**
* cairo_toy_font_face_get_slant:
* @font_face: A toy font face
*
* Gets the slant a toy font.
*
* Return value: The slant value
*
* Since: 1.8
**/
cairo_font_slant_t
cairo_toy_font_face_get_slant (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_SLANT_DEFAULT;
}
return toy_font_face->slant;
}
slim_hidden_def (cairo_toy_font_face_get_slant);
/**
* cairo_toy_font_face_get_weight:
* @font_face: A toy font face
*
* Gets the weight a toy font.
*
* Return value: The weight value
*
* Since: 1.8
**/
cairo_font_weight_t
cairo_toy_font_face_get_weight (cairo_font_face_t *font_face)
{
cairo_toy_font_face_t *toy_font_face = (cairo_toy_font_face_t *) font_face;
if (! _cairo_font_face_is_toy (font_face)) {
if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
return CAIRO_FONT_WEIGHT_DEFAULT;
}
return toy_font_face->weight;
}
slim_hidden_def (cairo_toy_font_face_get_weight);
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
CAIRO_FONT_TYPE_TOY,
_cairo_toy_font_face_destroy,
_cairo_toy_font_face_scaled_font_get_implementation,
_cairo_toy_font_face_scaled_font_create
};
void
_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
const cairo_unscaled_font_backend_t *backend)
{
CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
unscaled_font->backend = backend;
}
cairo_unscaled_font_t *
_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return NULL;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
_cairo_reference_count_inc (&unscaled_font->ref_count);
return unscaled_font;
}
void
_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
{
if (unscaled_font == NULL)
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count))
return;
unscaled_font->backend->destroy (unscaled_font);
free (unscaled_font);
}
void
_cairo_font_face_reset_static_data (void)
{
_cairo_scaled_font_map_destroy ();
/* We manually acquire the lock rather than calling
* cairo_toy_font_face_hash_table_lock simply to avoid
* creating the table only to destroy it again. */
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
_cairo_hash_table_destroy (cairo_toy_font_face_hash_table);
cairo_toy_font_face_hash_table = NULL;
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
}

View file

@ -0,0 +1,406 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
*/
#include "cairoint.h"
static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
};
/**
* _cairo_font_options_init_default:
* @options: a #cairo_font_options_t
*
* Initializes all fields of the font options object to default values.
**/
void
_cairo_font_options_init_default (cairo_font_options_t *options)
{
options->antialias = CAIRO_ANTIALIAS_DEFAULT;
options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
options->hint_style = CAIRO_HINT_STYLE_DEFAULT;
options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT;
}
void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
options->antialias = other->antialias;
options->subpixel_order = other->subpixel_order;
options->hint_style = other->hint_style;
options->hint_metrics = other->hint_metrics;
}
/**
* cairo_font_options_create:
*
* Allocates a new font options object with all options initialized
* to default values.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
**/
cairo_font_options_t *
cairo_font_options_create (void)
{
cairo_font_options_t *options;
options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *) &_cairo_font_options_nil;
}
_cairo_font_options_init_default (options);
return options;
}
/**
* cairo_font_options_copy:
* @original: a #cairo_font_options_t
*
* Allocates a new font options object copying the option values from
* @original.
*
* Return value: a newly allocated #cairo_font_options_t. Free with
* cairo_font_options_destroy(). This function always returns a
* valid pointer; if memory cannot be allocated, then a special
* error object is returned where all operations on the object do nothing.
* You can check for this with cairo_font_options_status().
**/
cairo_font_options_t *
cairo_font_options_copy (const cairo_font_options_t *original)
{
cairo_font_options_t *options;
if (cairo_font_options_status ((cairo_font_options_t *) original))
return (cairo_font_options_t *) &_cairo_font_options_nil;
options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *) &_cairo_font_options_nil;
}
_cairo_font_options_init_copy (options, original);
return options;
}
/**
* cairo_font_options_destroy:
* @options: a #cairo_font_options_t
*
* Destroys a #cairo_font_options_t object created with with
* cairo_font_options_create() or cairo_font_options_copy().
**/
void
cairo_font_options_destroy (cairo_font_options_t *options)
{
if (cairo_font_options_status (options))
return;
free (options);
}
/**
* cairo_font_options_status:
* @options: a #cairo_font_options_t
*
* Checks whether an error has previously occurred for this
* font options object
*
* Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
**/
cairo_status_t
cairo_font_options_status (cairo_font_options_t *options)
{
if (options == NULL)
return CAIRO_STATUS_NULL_POINTER;
else if (options == (cairo_font_options_t *) &_cairo_font_options_nil)
return CAIRO_STATUS_NO_MEMORY;
else
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def (cairo_font_options_status);
/**
* cairo_font_options_merge:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Merges non-default options from @other into @options, replacing
* existing values. This operation can be thought of as somewhat
* similar to compositing @other onto @options with the operation
* of %CAIRO_OPERATION_OVER.
**/
void
cairo_font_options_merge (cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status (options))
return;
if (cairo_font_options_status ((cairo_font_options_t *) other))
return;
if (other->antialias != CAIRO_ANTIALIAS_DEFAULT)
options->antialias = other->antialias;
if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
options->subpixel_order = other->subpixel_order;
if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT)
options->hint_style = other->hint_style;
if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT)
options->hint_metrics = other->hint_metrics;
}
slim_hidden_def (cairo_font_options_merge);
/**
* cairo_font_options_equal:
* @options: a #cairo_font_options_t
* @other: another #cairo_font_options_t
*
* Compares two font options objects for equality.
*
* Return value: %TRUE if all fields of the two font options objects match.
* Note that this function will return %FALSE if either object is in
* error.
**/
cairo_bool_t
cairo_font_options_equal (const cairo_font_options_t *options,
const cairo_font_options_t *other)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return FALSE;
if (cairo_font_options_status ((cairo_font_options_t *) other))
return FALSE;
if (options == other)
return TRUE;
return (options->antialias == other->antialias &&
options->subpixel_order == other->subpixel_order &&
options->hint_style == other->hint_style &&
options->hint_metrics == other->hint_metrics);
}
slim_hidden_def (cairo_font_options_equal);
/**
* cairo_font_options_hash:
* @options: a #cairo_font_options_t
*
* Compute a hash for the font options object; this value will
* be useful when storing an object containing a #cairo_font_options_t
* in a hash table.
*
* Return value: the hash value for the font options object.
* The return value can be cast to a 32-bit type if a
* 32-bit hash value is needed.
**/
unsigned long
cairo_font_options_hash (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
options = &_cairo_font_options_nil; /* force default values */
return ((options->antialias) |
(options->subpixel_order << 4) |
(options->hint_style << 8) |
(options->hint_metrics << 16));
}
slim_hidden_def (cairo_font_options_hash);
/**
* cairo_font_options_set_antialias:
* @options: a #cairo_font_options_t
* @antialias: the new antialiasing mode
*
* Sets the antialiasing mode for the font options object. This
* specifies the type of antialiasing to do when rendering text.
**/
void
cairo_font_options_set_antialias (cairo_font_options_t *options,
cairo_antialias_t antialias)
{
if (cairo_font_options_status (options))
return;
options->antialias = antialias;
}
slim_hidden_def (cairo_font_options_set_antialias);
/**
* cairo_font_options_get_antialias:
* @options: a #cairo_font_options_t
*
* Gets the antialiasing mode for the font options object.
*
* Return value: the antialiasing mode
**/
cairo_antialias_t
cairo_font_options_get_antialias (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_ANTIALIAS_DEFAULT;
return options->antialias;
}
/**
* cairo_font_options_set_subpixel_order:
* @options: a #cairo_font_options_t
* @subpixel_order: the new subpixel order
*
* Sets the subpixel order for the font options object. The subpixel
* order specifies the order of color elements within each pixel on
* the display device when rendering with an antialiasing mode of
* %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for
* #cairo_subpixel_order_t for full details.
**/
void
cairo_font_options_set_subpixel_order (cairo_font_options_t *options,
cairo_subpixel_order_t subpixel_order)
{
if (cairo_font_options_status (options))
return;
options->subpixel_order = subpixel_order;
}
slim_hidden_def (cairo_font_options_set_subpixel_order);
/**
* cairo_font_options_get_subpixel_order:
* @options: a #cairo_font_options_t
*
* Gets the subpixel order for the font options object.
* See the documentation for #cairo_subpixel_order_t for full details.
*
* Return value: the subpixel order for the font options object
**/
cairo_subpixel_order_t
cairo_font_options_get_subpixel_order (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_SUBPIXEL_ORDER_DEFAULT;
return options->subpixel_order;
}
/**
* cairo_font_options_set_hint_style:
* @options: a #cairo_font_options_t
* @hint_style: the new hint style
*
* Sets the hint style for font outlines for the font options object.
* This controls whether to fit font outlines to the pixel grid,
* and if so, whether to optimize for fidelity or contrast.
* See the documentation for #cairo_hint_style_t for full details.
**/
void
cairo_font_options_set_hint_style (cairo_font_options_t *options,
cairo_hint_style_t hint_style)
{
if (cairo_font_options_status (options))
return;
options->hint_style = hint_style;
}
slim_hidden_def (cairo_font_options_set_hint_style);
/**
* cairo_font_options_get_hint_style:
* @options: a #cairo_font_options_t
*
* Gets the hint style for font outlines for the font options object.
* See the documentation for #cairo_hint_style_t for full details.
*
* Return value: the hint style for the font options object
**/
cairo_hint_style_t
cairo_font_options_get_hint_style (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_STYLE_DEFAULT;
return options->hint_style;
}
/**
* cairo_font_options_set_hint_metrics:
* @options: a #cairo_font_options_t
* @hint_metrics: the new metrics hinting mode
*
* Sets the metrics hinting mode for the font options object. This
* controls whether metrics are quantized to integer values in
* device units.
* See the documentation for #cairo_hint_metrics_t for full details.
**/
void
cairo_font_options_set_hint_metrics (cairo_font_options_t *options,
cairo_hint_metrics_t hint_metrics)
{
if (cairo_font_options_status (options))
return;
options->hint_metrics = hint_metrics;
}
slim_hidden_def (cairo_font_options_set_hint_metrics);
/**
* cairo_font_options_get_hint_metrics:
* @options: a #cairo_font_options_t
*
* Gets the metrics hinting mode for the font options object.
* See the documentation for #cairo_hint_metrics_t for full details.
*
* Return value: the metrics hinting mode for the font options object
**/
cairo_hint_metrics_t
cairo_font_options_get_hint_metrics (const cairo_font_options_t *options)
{
if (cairo_font_options_status ((cairo_font_options_t *) options))
return CAIRO_HINT_METRICS_DEFAULT;
return options->hint_metrics;
}

View file

@ -0,0 +1,71 @@
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef CAIRO_FREELIST_H
#define CAIRO_FREELIST_H
#include "cairo-types-private.h"
#include "cairo-compiler-private.h"
/* Opaque implementation types. */
typedef struct _cairo_freelist cairo_freelist_t;
typedef struct _cairo_freelist_node cairo_freelist_node_t;
struct _cairo_freelist_node {
cairo_freelist_node_t *next;
};
struct _cairo_freelist {
cairo_freelist_node_t *first_free_node;
unsigned nodesize;
};
/* Initialise a freelist that will be responsible for allocating
* nodes of size nodesize. */
cairo_private void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize);
/* Deallocate any nodes in the freelist. */
cairo_private void
_cairo_freelist_fini (cairo_freelist_t *freelist);
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using malloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_alloc (cairo_freelist_t *freelist);
/* Allocate a new node from the freelist. If the freelist contains no
* nodes, a new one will be allocated using calloc(). The caller is
* responsible for calling _cairo_freelist_free() or free() on the
* returned node. Returns %NULL on memory allocation error. */
cairo_private void *
_cairo_freelist_calloc (cairo_freelist_t *freelist);
/* Return a node to the freelist. This does not deallocate the memory,
* but makes it available for later reuse by
* _cairo_freelist_alloc(). */
cairo_private void
_cairo_freelist_free (cairo_freelist_t *freelist, void *node);
#endif /* CAIRO_FREELIST_H */

View file

@ -0,0 +1,73 @@
/*
* Copyright © 2006 Joonas Pihlaja
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "cairoint.h"
#include "cairo-freelist-private.h"
void
_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize)
{
memset (freelist, 0, sizeof(cairo_freelist_t));
freelist->nodesize = nodesize;
}
void
_cairo_freelist_fini (cairo_freelist_t *freelist)
{
cairo_freelist_node_t *node = freelist->first_free_node;
while (node) {
cairo_freelist_node_t *next = node->next;
free (node);
node = next;
}
}
void *
_cairo_freelist_alloc (cairo_freelist_t *freelist)
{
if (freelist->first_free_node) {
cairo_freelist_node_t *node = freelist->first_free_node;
freelist->first_free_node = node->next;
return (void*)node;
}
return malloc (freelist->nodesize);
}
void *
_cairo_freelist_calloc (cairo_freelist_t *freelist)
{
void *node = _cairo_freelist_alloc (freelist);
if (node)
memset (node, 0, freelist->nodesize);
return node;
}
void
_cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
{
cairo_freelist_node_t *node = voidnode;
if (node) {
node->next = freelist->first_free_node;
freelist->first_free_node = node;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,70 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#ifndef CAIRO_FT_PRIVATE_H
#define CAIRO_FT_PRIVATE_H
#include "cairo-ft.h"
#include "cairoint.h"
#if CAIRO_HAS_FT_FONT
CAIRO_BEGIN_DECLS
typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
cairo_private cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
/* These functions are needed by the PDF backend, which needs to keep track of the
* the different fonts-on-disk used by a document, so it can embed them
*/
cairo_private cairo_unscaled_font_t *
_cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *scaled_font);
cairo_private FT_Face
_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private void
_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_PRIVATE_H */

View file

@ -0,0 +1,75 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Graydon Hoare <graydon@redhat.com>
* Owen Taylor <otaylor@redhat.com>
*/
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
#include "cairo.h"
#if CAIRO_HAS_FT_FONT
/* Fontconfig/Freetype platform-specific font interface */
#include <fontconfig/fontconfig.h>
#include <ft2build.h>
#include FT_FREETYPE_H
CAIRO_BEGIN_DECLS
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
cairo_public void
cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern);
cairo_public cairo_font_face_t *
cairo_ft_font_face_create_for_ft_face (FT_Face face,
int load_flags);
cairo_public FT_Face
cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font);
cairo_public void
cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font);
CAIRO_END_DECLS
#else /* CAIRO_HAS_FT_FONT */
# error Cairo was not compiled with support for the freetype font backend
#endif /* CAIRO_HAS_FT_FONT */
#endif /* CAIRO_FT_H */

View file

@ -0,0 +1,41 @@
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*/
#ifndef CAIRO_GLITZ_PRIVATE_H
#define CAIRO_GLITZ_PRIVATE_H
#include "cairoint.h"
#include "cairo-glitz.h"
slim_hidden_proto (cairo_glitz_surface_create);
#endif /* CAIRO_GLITZ_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,57 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_GLITZ_H
#define CAIRO_GLITZ_H
#include "cairo.h"
#if CAIRO_HAS_GLITZ_SURFACE
#include <glitz.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_glitz_surface_create (glitz_surface_t *surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_GLITZ_SURFACE */
# error Cairo was not compiled with support for the glitz backend
#endif /* CAIRO_HAS_GLITZ_SURFACE */
#endif /* CAIRO_GLITZ_H */

View file

@ -0,0 +1,71 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_GSTATE_PRIVATE_H
#define CAIRO_GSTATE_PRIVATE_H
#include "cairo-clip-private.h"
struct _cairo_gstate {
cairo_operator_t op;
double tolerance;
cairo_antialias_t antialias;
cairo_stroke_style_t stroke_style;
cairo_fill_rule_t fill_rule;
cairo_font_face_t *font_face;
cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */
cairo_matrix_t font_matrix;
cairo_font_options_t font_options;
cairo_clip_t clip;
cairo_surface_t *target; /* The target to which all rendering is directed */
cairo_surface_t *parent_target; /* The previous target which was receiving rendering */
cairo_surface_t *original_target; /* The original target the initial gstate was created with */
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */
cairo_pattern_t *source;
struct _cairo_gstate *next;
};
#endif /* CAIRO_GSTATE_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#ifndef CAIRO_HASH_PRIVATE_H
#define CAIRO_HASH_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/* XXX: I'd like this file to be self-contained in terms of
* includeability, but that's not really possible with the current
* monolithic cairoint.h. So, for now, just include cairoint.h instead
* if you want to include this file. */
typedef cairo_bool_t
(*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef cairo_bool_t
(*cairo_hash_predicate_func_t) (void *entry);
typedef void
(*cairo_hash_callback_func_t) (void *entry,
void *closure);
cairo_private cairo_hash_table_t *
_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal);
cairo_private void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table);
cairo_private cairo_bool_t
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key,
cairo_hash_entry_t **entry_return);
cairo_private void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
cairo_hash_predicate_func_t predicate);
cairo_private cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *entry);
cairo_private void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key);
cairo_private void
_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure);
#endif

View file

@ -0,0 +1,576 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc.
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Keith Packard <keithp@keithp.com>
* Graydon Hoare <graydon@redhat.com>
* Carl Worth <cworth@cworth.org>
*/
#include "cairoint.h"
/*
* An entry can be in one of three states:
*
* FREE: Entry has never been used, terminates all searches.
* Appears in the table as a %NULL pointer.
*
* DEAD: Entry had been live in the past. A dead entry can be reused
* but does not terminate a search for an exact entry.
* Appears in the table as a pointer to DEAD_ENTRY.
*
* LIVE: Entry is currently being used.
* Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
*/
static cairo_hash_entry_t dead_entry = { 0 };
#define DEAD_ENTRY (&dead_entry)
#define ENTRY_IS_FREE(entry) ((entry) == NULL)
#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
#define ENTRY_IS_LIVE(entry) ((entry) && ! ENTRY_IS_DEAD(entry))
/* We expect keys will not be destroyed frequently, so our table does not
* contain any explicit shrinking code nor any chain-coalescing code for
* entries randomly deleted by memory pressure (except during rehashing, of
* course). These assumptions are potentially bad, but they make the
* implementation straightforward.
*
* Revisit later if evidence appears that we're using excessive memory from
* a mostly-dead table.
*
* This table is open-addressed with double hashing. Each table size is a
* prime chosen to be a little more than double the high water mark for a
* given arrangement, so the tables should remain < 50% full. The table
* size makes for the "first" hash modulus; a second prime (2 less than the
* first prime) serves as the "second" hash modulus, which is co-prime and
* thus guarantees a complete permutation of table indices.
*
* This structure, and accompanying table, is borrowed/modified from the
* file xserver/render/glyph.c in the freedesktop.org x server, with
* permission (and suggested modification of doubling sizes) by Keith
* Packard.
*/
typedef struct _cairo_hash_table_arrangement {
unsigned long high_water_mark;
unsigned long size;
unsigned long rehash;
} cairo_hash_table_arrangement_t;
static const cairo_hash_table_arrangement_t hash_table_arrangements [] = {
{ 16, 43, 41 },
{ 32, 73, 71 },
{ 64, 151, 149 },
{ 128, 283, 281 },
{ 256, 571, 569 },
{ 512, 1153, 1151 },
{ 1024, 2269, 2267 },
{ 2048, 4519, 4517 },
{ 4096, 9013, 9011 },
{ 8192, 18043, 18041 },
{ 16384, 36109, 36107 },
{ 32768, 72091, 72089 },
{ 65536, 144409, 144407 },
{ 131072, 288361, 288359 },
{ 262144, 576883, 576881 },
{ 524288, 1153459, 1153457 },
{ 1048576, 2307163, 2307161 },
{ 2097152, 4613893, 4613891 },
{ 4194304, 9227641, 9227639 },
{ 8388608, 18455029, 18455027 },
{ 16777216, 36911011, 36911009 },
{ 33554432, 73819861, 73819859 },
{ 67108864, 147639589, 147639587 },
{ 134217728, 295279081, 295279079 },
{ 268435456, 590559793, 590559791 }
};
#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements)
struct _cairo_hash_table {
cairo_hash_keys_equal_func_t keys_equal;
const cairo_hash_table_arrangement_t *arrangement;
cairo_hash_entry_t **entries;
unsigned long live_entries;
unsigned long iterating; /* Iterating, no insert, no resize */
};
/**
* _cairo_hash_table_create:
* @keys_equal: a function to return %TRUE if two keys are equal
*
* Creates a new hash table which will use the keys_equal() function
* to compare hash keys. Data is provided to the hash table in the
* form of user-derived versions of #cairo_hash_entry_t. A hash entry
* must be able to hold both a key (including a hash code) and a
* value. Sometimes only the key will be necessary, (as in
* _cairo_hash_table_remove), and other times both a key and a value
* will be necessary, (as in _cairo_hash_table_insert).
*
* See #cairo_hash_entry_t for more details.
*
* Return value: the new hash table or %NULL if out of memory.
**/
cairo_hash_table_t *
_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
{
cairo_hash_table_t *hash_table;
hash_table = malloc (sizeof (cairo_hash_table_t));
if (hash_table == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
hash_table->keys_equal = keys_equal;
hash_table->arrangement = &hash_table_arrangements[0];
hash_table->entries = calloc (hash_table->arrangement->size,
sizeof(cairo_hash_entry_t *));
if (hash_table->entries == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (hash_table);
return NULL;
}
hash_table->live_entries = 0;
hash_table->iterating = 0;
return hash_table;
}
/**
* _cairo_hash_table_destroy:
* @hash_table: an empty hash table to destroy
*
* Immediately destroys the given hash table, freeing all resources
* associated with it.
*
* WARNING: The hash_table must have no live entries in it before
* _cairo_hash_table_destroy is called. It is a fatal error otherwise,
* and this function will halt. The rationale for this behavior is to
* avoid memory leaks and to avoid needless complication of the API
* with destroy notifiy callbacks.
*
* WARNING: The hash_table must have no running iterators in it when
* _cairo_hash_table_destroy is called. It is a fatal error otherwise,
* and this function will halt.
**/
void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
{
if (hash_table == NULL)
return;
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
/* No iterators can be running. Otherwise, halt. */
assert (hash_table->iterating == 0);
free (hash_table->entries);
hash_table->entries = NULL;
free (hash_table);
}
/**
* _cairo_hash_table_lookup_internal:
*
* @hash_table: a #cairo_hash_table_t to search
* @key: the key to search on
* @hash_code: the hash_code for @key
* @key_unique: If %TRUE, then caller asserts that no key already
* exists that will compare equal to #key, so search can be
* optimized. If unsure, set to %FALSE and the code will always work.
*
* Search the hashtable for a live entry for which
* hash_table->keys_equal returns true. If no such entry exists then
* return the first available (free or dead entry).
*
* If the key_unique flag is set, then the search will never call
* hash_table->keys_equal and will act as if it always returned
* false. This is useful as a performance optimization in special
* circumstances where the caller knows that there is no existing
* entry in the hash table with a matching key.
*
* Return value: The matching entry in the hash table (if
* any). Otherwise, the first available entry. The caller should check
* entry->state to check whether a match was found or not.
**/
static cairo_hash_entry_t **
_cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key,
cairo_bool_t key_is_unique)
{
cairo_hash_entry_t **entry, **first_available = NULL;
unsigned long table_size, i, idx, step;
table_size = hash_table->arrangement->size;
idx = key->hash % table_size;
step = 0;
for (i = 0; i < table_size; ++i)
{
entry = &hash_table->entries[idx];
if (ENTRY_IS_FREE(*entry))
{
return entry;
}
else if (ENTRY_IS_DEAD(*entry))
{
if (key_is_unique) {
return entry;
} else {
if (! first_available)
first_available = entry;
}
}
else /* ENTRY_IS_LIVE(*entry) */
{
if (! key_is_unique)
if (hash_table->keys_equal (key, *entry))
return entry;
}
if (step == 0) {
step = key->hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
}
idx += step;
if (idx >= table_size)
idx -= table_size;
}
/*
* The table should not have permitted you to get here if you were just
* looking for a free slot: there should have been room.
*/
assert (key_is_unique == 0);
return first_available;
}
/**
* _cairo_hash_table_resize:
* @hash_table: a hash table
*
* Resize the hash table if the number of entries has gotten much
* bigger or smaller than the ideal number of entries for the current
* size.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
static cairo_status_t
_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
{
cairo_hash_table_t tmp;
cairo_hash_entry_t **entry;
unsigned long new_size, i;
/* This keeps the hash table between 25% and 50% full. */
unsigned long high = hash_table->arrangement->high_water_mark;
unsigned long low = high >> 2;
if (hash_table->live_entries >= low && hash_table->live_entries <= high)
return CAIRO_STATUS_SUCCESS;
tmp = *hash_table;
if (hash_table->live_entries > high)
{
tmp.arrangement = hash_table->arrangement + 1;
/* This code is being abused if we can't make a table big enough. */
assert (tmp.arrangement - hash_table_arrangements <
NUM_HASH_TABLE_ARRANGEMENTS);
}
else /* hash_table->live_entries < low */
{
/* Can't shrink if we're at the smallest size */
if (hash_table->arrangement == &hash_table_arrangements[0])
return CAIRO_STATUS_SUCCESS;
tmp.arrangement = hash_table->arrangement - 1;
}
new_size = tmp.arrangement->size;
tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*));
if (tmp.entries == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < hash_table->arrangement->size; ++i) {
if (ENTRY_IS_LIVE (hash_table->entries[i])) {
entry = _cairo_hash_table_lookup_internal (&tmp,
hash_table->entries[i],
TRUE);
assert (ENTRY_IS_FREE(*entry));
*entry = hash_table->entries[i];
}
}
free (hash_table->entries);
hash_table->entries = tmp.entries;
hash_table->arrangement = tmp.arrangement;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_hash_table_lookup:
* @hash_table: a hash table
* @key: the key of interest
* @entry_return: pointer for return value.
*
* Performs a lookup in @hash_table looking for an entry which has a
* key that matches @key, (as determined by the keys_equal() function
* passed to _cairo_hash_table_create).
*
* Return value: %TRUE if there is an entry in the hash table that
* matches the given key, (which will now be in *entry_return). %FALSE
* otherwise, (in which case *entry_return will be %NULL).
**/
cairo_bool_t
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key,
cairo_hash_entry_t **entry_return)
{
cairo_hash_entry_t **entry;
/* See if we have an entry in the table already. */
entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE);
if (ENTRY_IS_LIVE(*entry)) {
*entry_return = *entry;
return TRUE;
}
*entry_return = NULL;
return FALSE;
}
/**
* _cairo_hash_table_random_entry:
* @hash_table: a hash table
* @predicate: a predicate function, or %NULL for any entry.
*
* Find a random entry in the hash table satisfying the given
* @predicate. A %NULL @predicate is taken as equivalent to a function
* which always returns %TRUE, (eg. any entry in the table will do).
*
* We use the same algorithm as the lookup algorithm to walk over the
* entries in the hash table in a pseudo-random order. Walking
* linearly would favor entries following gaps in the hash table. We
* could also call rand() repeatedly, which works well for almost-full
* tables, but degrades when the table is almost empty, or predicate
* returns %TRUE for most entries.
*
* Return value: a random live entry or %NULL if there are no entries
* that match the given predicate. In particular, if predicate is
* %NULL, a %NULL return value indicates that the table is empty.
**/
void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
cairo_hash_predicate_func_t predicate)
{
cairo_hash_entry_t **entry;
unsigned long hash;
unsigned long table_size, i, idx, step;
table_size = hash_table->arrangement->size;
hash = rand ();
idx = hash % table_size;
step = 0;
for (i = 0; i < table_size; ++i)
{
entry = &hash_table->entries[idx];
if (ENTRY_IS_LIVE (*entry) &&
(predicate == NULL || predicate (*entry)))
{
return *entry;
}
if (step == 0) {
step = hash % hash_table->arrangement->rehash;
if (step == 0)
step = 1;
}
idx += step;
if (idx >= table_size)
idx -= table_size;
}
return NULL;
}
/**
* _cairo_hash_table_insert:
* @hash_table: a hash table
* @key_and_value: an entry to be inserted
*
* Insert the entry #key_and_value into the hash table.
*
* WARNING: It is a fatal error if an entry exists in the hash table
* with a matching key, (this function will halt).
*
* WARNING: It is a fatal error to insert an element while
* an iterator is running
*
* Instead of using insert to replace an entry, consider just editing
* the entry obtained with _cairo_hash_table_lookup. Or if absolutely
* necessary, use _cairo_hash_table_remove first.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key_and_value)
{
cairo_status_t status;
cairo_hash_entry_t **entry;
/* Insert is illegal while an iterator is running. */
assert (hash_table->iterating == 0);
entry = _cairo_hash_table_lookup_internal (hash_table,
key_and_value, FALSE);
if (ENTRY_IS_LIVE(*entry))
{
/* User is being bad, let's crash. */
ASSERT_NOT_REACHED;
}
*entry = key_and_value;
hash_table->live_entries++;
status = _cairo_hash_table_resize (hash_table);
if (status) {
/* abort the insert... */
*entry = DEAD_ENTRY;
hash_table->live_entries--;
return status;
}
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_hash_table_remove:
* @hash_table: a hash table
* @key: key of entry to be removed
*
* Remove an entry from the hash table which has a key that matches
* @key, if any (as determined by the keys_equal() function passed to
* _cairo_hash_table_create).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
cairo_hash_entry_t **entry;
entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE);
if (! ENTRY_IS_LIVE(*entry))
return;
*entry = DEAD_ENTRY;
hash_table->live_entries--;
/* Check for table resize. Don't do this when iterating as this will
* reorder elements of the table and cause the iteration to potentially
* skip some elements. */
if (hash_table->iterating == 0) {
/* This call _can_ fail, but only in failing to allocate new
* memory to shrink the hash table. It does leave the table in a
* consistent state, and we've already succeeded in removing the
* entry, so we don't examine the failure status of this call. */
_cairo_hash_table_resize (hash_table);
}
}
/**
* _cairo_hash_table_foreach:
* @hash_table: a hash table
* @hash_callback: function to be called for each live entry
* @closure: additional argument to be passed to @hash_callback
*
* Call @hash_callback for each live entry in the hash table, in a
* non-specified order.
*
* Entries in @hash_table may be removed by code executed from @hash_callback.
*
* Entries may not be inserted to @hash_table, nor may @hash_table
* be destroyed by code executed from @hash_callback. The relevant
* functions will halt in these cases.
**/
void
_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure)
{
unsigned long i;
cairo_hash_entry_t *entry;
if (hash_table == NULL)
return;
/* Mark the table for iteration */
++hash_table->iterating;
for (i = 0; i < hash_table->arrangement->size; i++) {
entry = hash_table->entries[i];
if (ENTRY_IS_LIVE(entry))
hash_callback (entry, closure);
}
/* If some elements were deleted during the iteration,
* the table may need resizing. Just do this every time
* as the check is inexpensive.
*/
if (--hash_table->iterating == 0) {
/* Should we fail to shrink the hash table, it is left unaltered,
* and we don't need to propagate the error status. */
_cairo_hash_table_resize (hash_table);
}
}

View file

@ -0,0 +1,222 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;
int discard;
int id;
} cairo_hull_t;
static void
_cairo_hull_init (cairo_hull_t *hull,
cairo_pen_vertex_t *vertices,
int num_vertices)
{
cairo_point_t *p, *extremum, tmp;
int i;
extremum = &vertices[0].point;
for (i = 1; i < num_vertices; i++) {
p = &vertices[i].point;
if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
extremum = p;
}
/* Put the extremal point at the beginning of the array */
tmp = *extremum;
*extremum = vertices[0].point;
vertices[0].point = tmp;
for (i = 0; i < num_vertices; i++) {
hull[i].point = vertices[i].point;
_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
/* give each point a unique id for later comparison */
hull[i].id = i;
/* Don't discard by default */
hull[i].discard = 0;
/* Discard all points coincident with the extremal point */
if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
hull[i].discard = 1;
}
}
static inline cairo_int64_t
_slope_length (cairo_slope_t *slope)
{
return _cairo_int64_add (_cairo_int32x32_64_mul (slope->dx, slope->dx),
_cairo_int32x32_64_mul (slope->dy, slope->dy));
}
static int
_cairo_hull_vertex_compare (const void *av, const void *bv)
{
cairo_hull_t *a = (cairo_hull_t *) av;
cairo_hull_t *b = (cairo_hull_t *) bv;
int ret;
ret = _cairo_slope_compare (&a->slope, &b->slope);
/*
* In the case of two vertices with identical slope from the
* extremal point discard the nearer point.
*/
if (ret == 0) {
int cmp;
cmp = _cairo_int64_cmp (_slope_length (&a->slope),
_slope_length (&b->slope));
/*
* Use the points' ids to ensure a well-defined ordering,
* and avoid setting discard on both points.
*/
if (cmp < 0 || (cmp == 0 && a->id < b->id)) {
a->discard = 1;
ret = -1;
} else {
b->discard = 1;
ret = 1;
}
}
return ret;
}
static int
_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
{
/* hull[0] is always valid, and we never need to wraparound, (if
* we are passed an index of 0 here, then the calling loop is just
* about to terminate). */
if (index == 0)
return 0;
do {
index--;
} while (hull[index].discard);
return index;
}
static int
_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
{
do {
index = (index + 1) % num_hull;
} while (hull[index].discard);
return index;
}
static void
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
{
int i, j, k;
cairo_slope_t slope_ij, slope_jk;
i = 0;
j = _cairo_hull_next_valid (hull, num_hull, i);
k = _cairo_hull_next_valid (hull, num_hull, j);
do {
_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
/* Is the angle formed by ij and jk concave? */
if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
if (i == k)
return;
hull[j].discard = 1;
j = i;
i = _cairo_hull_prev_valid (hull, num_hull, j);
} else {
i = j;
j = k;
k = _cairo_hull_next_valid (hull, num_hull, j);
}
} while (j != 0);
}
static void
_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
{
int i, j = 0;
for (i = 0; i < *num_vertices; i++) {
if (hull[i].discard)
continue;
vertices[j++].point = hull[i].point;
}
*num_vertices = j;
}
/* Given a set of vertices, compute the convex hull using the Graham
scan algorithm. */
cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
{
cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
cairo_hull_t *hull;
int num_hull = *num_vertices;
if (num_hull > ARRAY_LENGTH (hull_stack)) {
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
if (hull == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
hull = hull_stack;
}
_cairo_hull_init (hull, vertices, num_hull);
qsort (hull + 1, num_hull - 1,
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
_cairo_hull_eliminate_concave (hull, num_hull);
_cairo_hull_to_pen (hull, vertices, num_vertices);
if (hull != hull_stack)
free (hull);
return CAIRO_STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,403 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
typedef struct _lzw_buf {
cairo_status_t status;
unsigned char *data;
int data_size;
int num_data;
uint32_t pending;
unsigned int pending_bits;
} lzw_buf_t;
/* An lzw_buf_t is a simple, growable chunk of memory for holding
* variable-size objects of up to 16 bits each.
*
* Initialize an lzw_buf_t to the given size in bytes.
*
* To store objects into the lzw_buf_t, call _lzw_buf_store_bits and
* when finished, call _lzw_buf_store_pending, (which flushes out the
* last few bits that hadn't yet made a complete byte yet).
*
* Instead of returning failure from any functions, lzw_buf_t provides
* a status value that the caller can query, (and should query at
* least once when done with the object). The status value will be
* either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY;
*/
static void
_lzw_buf_init (lzw_buf_t *buf, int size)
{
if (size == 0)
size = 16;
buf->status = CAIRO_STATUS_SUCCESS;
buf->data_size = size;
buf->num_data = 0;
buf->pending = 0;
buf->pending_bits = 0;
buf->data = malloc (size);
if (buf->data == NULL) {
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
}
}
/* Increase the buffer size by doubling.
*
* Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*/
static cairo_status_t
_lzw_buf_grow (lzw_buf_t *buf)
{
int new_size = buf->data_size * 2;
unsigned char *new_data;
if (buf->status)
return buf->status;
new_data = NULL;
/* check for integer overflow */
if (new_size / 2 == buf->data_size)
new_data = realloc (buf->data, new_size);
if (new_data == NULL) {
free (buf->data);
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return buf->status;
}
buf->data = new_data;
buf->data_size = new_size;
return CAIRO_STATUS_SUCCESS;
}
/* Store the lowest num_bits bits of values into buf.
*
* Note: The bits of value above size_in_bits must be 0, (so don't lie
* about the size).
*
* See also _lzw_buf_store_pending which must be called after the last
* call to _lzw_buf_store_bits.
*
* Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
*/
static void
_lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits)
{
cairo_status_t status;
assert (value <= (1 << num_bits) - 1);
if (buf->status)
return;
buf->pending = (buf->pending << num_bits) | value;
buf->pending_bits += num_bits;
while (buf->pending_bits >= 8) {
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
if (status)
return;
}
buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8);
buf->pending_bits -= 8;
}
}
/* Store the last remaining pending bits into the buffer.
*
* Note: This function must be called after the last call to
* _lzw_buf_store_bits.
*
* Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY.
*/
static void
_lzw_buf_store_pending (lzw_buf_t *buf)
{
cairo_status_t status;
if (buf->status)
return;
if (buf->pending_bits == 0)
return;
assert (buf->pending_bits < 8);
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
if (status)
return;
}
buf->data[buf->num_data++] = buf->pending << (8 - buf->pending_bits);
buf->pending_bits = 0;
}
/* LZW defines a few magic code values */
#define LZW_CODE_CLEAR_TABLE 256
#define LZW_CODE_EOD 257
#define LZW_CODE_FIRST 258
/* We pack three separate values into a symbol as follows:
*
* 12 bits (31 down to 20): CODE: code value used to represent this symbol
* 12 bits (19 down to 8): PREV: previous code value in chain
* 8 bits ( 7 down to 0): NEXT: next byte value in chain
*/
typedef uint32_t lzw_symbol_t;
#define LZW_SYMBOL_SET(sym, prev, next) ((sym) = ((prev) << 8)|(next))
#define LZW_SYMBOL_SET_CODE(sym, code, prev, next) ((sym) = ((code << 20)|(prev) << 8)|(next))
#define LZW_SYMBOL_GET_CODE(sym) (((sym) >> 20))
#define LZW_SYMBOL_GET_PREV(sym) (((sym) >> 8) & 0x7ff)
#define LZW_SYMBOL_GET_BYTE(sym) (((sym) >> 0) & 0x0ff)
/* The PREV+NEXT fields can be seen as the key used to fetch values
* from the hash table, while the code is the value fetched.
*/
#define LZW_SYMBOL_KEY_MASK 0x000fffff
/* Since code values are only stored starting with 258 we can safely
* use a zero value to represent free slots in the hash table. */
#define LZW_SYMBOL_FREE 0x00000000
/* These really aren't very free for modifying. First, the PostScript
* specification sets the 9-12 bit range. Second, the encoding of
* lzw_symbol_t above also relies on 2 of LZW_BITS_MAX plus one byte
* fitting within 32 bits.
*
* But other than that, the LZW compression scheme could function with
* more bits per code.
*/
#define LZW_BITS_MIN 9
#define LZW_BITS_MAX 12
#define LZW_BITS_BOUNDARY(bits) ((1<<(bits))-1)
#define LZW_MAX_SYMBOLS (1<<LZW_BITS_MAX)
#define LZW_SYMBOL_TABLE_SIZE 9013
#define LZW_SYMBOL_MOD1 LZW_SYMBOL_TABLE_SIZE
#define LZW_SYMBOL_MOD2 9011
typedef struct _lzw_symbol_table {
lzw_symbol_t table[LZW_SYMBOL_TABLE_SIZE];
} lzw_symbol_table_t;
/* Initialize the hash table to entirely empty */
static void
_lzw_symbol_table_init (lzw_symbol_table_t *table)
{
memset (table->table, 0, LZW_SYMBOL_TABLE_SIZE * sizeof (lzw_symbol_t));
}
/* Lookup a symbol in the symbol table. The PREV and NEXT fields of
* symbol form the key for the lookup.
*
* If successful, then this function returns %TRUE and slot_ret will be
* left pointing at the result that will have the CODE field of
* interest.
*
* If the lookup fails, then this function returns %FALSE and slot_ret
* will be pointing at the location in the table to which a new CODE
* value should be stored along with PREV and NEXT.
*/
static cairo_bool_t
_lzw_symbol_table_lookup (lzw_symbol_table_t *table,
lzw_symbol_t symbol,
lzw_symbol_t **slot_ret)
{
/* The algorithm here is identical to that in cairo-hash.c. We
* copy it here to allow for a rather more efficient
* implementation due to several circumstances that do not apply
* to the more general case:
*
* 1) We have a known bound on the total number of symbols, so we
* have a fixed-size table without any copying when growing
*
* 2) We never delete any entries, so we don't need to
* support/check for DEAD entries during lookup.
*
* 3) The object fits in 32 bits so we store each object in its
* entirety within the table rather than storing objects
* externally and putting pointers in the table, (which here
* would just double the storage requirements and have negative
* impacts on memory locality).
*/
int i, idx, step, hash = symbol & LZW_SYMBOL_KEY_MASK;
lzw_symbol_t candidate;
idx = hash % LZW_SYMBOL_MOD1;
step = 0;
*slot_ret = NULL;
for (i = 0; i < LZW_SYMBOL_TABLE_SIZE; i++)
{
candidate = table->table[idx];
if (candidate == LZW_SYMBOL_FREE)
{
*slot_ret = &table->table[idx];
return FALSE;
}
else /* candidate is LIVE */
{
if ((candidate & LZW_SYMBOL_KEY_MASK) ==
(symbol & LZW_SYMBOL_KEY_MASK))
{
*slot_ret = &table->table[idx];
return TRUE;
}
}
if (step == 0) {
step = hash % LZW_SYMBOL_MOD2;
if (step == 0)
step = 1;
}
idx += step;
if (idx >= LZW_SYMBOL_TABLE_SIZE)
idx -= LZW_SYMBOL_TABLE_SIZE;
}
return FALSE;
}
/* Compress a bytestream using the LZW algorithm.
*
* This is an original implementation based on reading the
* specification of the LZWDecode filter in the PostScript Language
* Reference. The free parameters in the LZW algorithm are set to the
* values mandated by PostScript, (symbols encoded with widths from 9
* to 12 bits).
*
* This function returns a pointer to a newly allocated buffer holding
* the compressed data, or %NULL if an out-of-memory situation
* occurs.
*
* Notice that any one of the _lzw_buf functions called here could
* trigger an out-of-memory condition. But lzw_buf_t uses cairo's
* shutdown-on-error idiom, so it's safe to continue to call into
* lzw_buf without having to check for errors, (until a final check at
* the end).
*/
unsigned char *
_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out)
{
int bytes_remaining = *size_in_out;
lzw_buf_t buf;
lzw_symbol_table_t table;
lzw_symbol_t symbol, *slot = NULL; /* just to squelch a warning */
int code_next = LZW_CODE_FIRST;
int code_bits = LZW_BITS_MIN;
int prev, next = 0; /* just to squelch a warning */
if (*size_in_out == 0)
return NULL;
_lzw_buf_init (&buf, *size_in_out);
_lzw_symbol_table_init (&table);
/* The LZW header is a clear table code. */
_lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits);
while (1) {
/* Find the longest existing code in the symbol table that
* matches the current input, if any. */
prev = *data++;
bytes_remaining--;
if (bytes_remaining) {
do
{
next = *data++;
bytes_remaining--;
LZW_SYMBOL_SET (symbol, prev, next);
if (_lzw_symbol_table_lookup (&table, symbol, &slot))
prev = LZW_SYMBOL_GET_CODE (*slot);
} while (bytes_remaining && *slot != LZW_SYMBOL_FREE);
if (*slot == LZW_SYMBOL_FREE) {
data--;
bytes_remaining++;
}
}
/* Write the code into the output. This is either a byte read
* directly from the input, or a code from the last successful
* lookup. */
_lzw_buf_store_bits (&buf, prev, code_bits);
if (bytes_remaining == 0)
break;
LZW_SYMBOL_SET_CODE (*slot, code_next++, prev, next);
if (code_next > LZW_BITS_BOUNDARY(code_bits))
{
code_bits++;
if (code_bits > LZW_BITS_MAX) {
_lzw_symbol_table_init (&table);
_lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits - 1);
code_bits = LZW_BITS_MIN;
code_next = LZW_CODE_FIRST;
}
}
}
/* The LZW footer is an end-of-data code. */
_lzw_buf_store_bits (&buf, LZW_CODE_EOD, code_bits);
_lzw_buf_store_pending (&buf);
/* See if we ever ran out of memory while writing to buf. */
if (buf.status == CAIRO_STATUS_NO_MEMORY) {
*size_in_out = 0;
return NULL;
}
assert (buf.status == CAIRO_STATUS_SUCCESS);
*size_in_out = buf.num_data;
return buf.data;
}

View file

@ -0,0 +1,141 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
*/
#ifndef CAIRO_MALLOC_PRIVATE_H
#define CAIRO_MALLOC_PRIVATE_H
#include "cairo-wideint-private.h"
/**
* _cairo_malloc:
* @size: size in bytes
*
* Allocate @size memory using malloc().
* The memory should be freed using free().
* malloc is skipped, if 0 bytes are requested, and %NULL will be returned.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or size is 0.
*/
#define _cairo_malloc(size) \
((size) ? malloc((unsigned) (size)) : NULL)
/**
* _cairo_malloc_ab:
* @n: number of elements to allocate
* @size: size of each element
*
* Allocates @n*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves much like
* calloc(), except that the returned memory is not set to zero.
* The memory should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_ab(a, size) \
((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (a) * (unsigned) (size)))
/**
* _cairo_realloc_ab:
* @ptr: original pointer to block of memory to be resized
* @n: number of elements to allocate
* @size: size of each element
*
* Reallocates @ptr a block of @n*@size memory using realloc(), taking
* care to not overflow when doing the multiplication. The memory
* should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of realloc() failure or overflow (whereupon the original block
* of memory * is left untouched).
*/
#define _cairo_realloc_ab(ptr, a, size) \
((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
realloc(ptr, (unsigned) (a) * (unsigned) (size)))
/**
* _cairo_malloc_abc:
* @n: first factor of number of elements to allocate
* @b: second factor of number of elements to allocate
* @size: size of each element
*
* Allocates @n*@b*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_abc(a, b, size) \
((b) && (unsigned) (a) >= INT32_MAX / (unsigned) (b) ? NULL : \
(size) && (unsigned) ((a)*(b)) >= INT32_MAX / (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (a) * (unsigned) (b) * (unsigned) (size)))
/**
* _cairo_malloc_ab_plus_c:
* @n: number of elements to allocate
* @size: size of each element
* @k: additional size to allocate
*
* Allocates @n*@ksize+@k memory using _cairo_malloc(), taking care to not
* overflow when doing the arithmetic. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free().
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of malloc() failure or overflow.
*/
#define _cairo_malloc_ab_plus_c(n, size, k) \
((size) && (unsigned) (n) >= INT32_MAX / (unsigned) (size) ? NULL : \
(unsigned) (k) >= INT32_MAX - (unsigned) (n) * (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (n) * (unsigned) (size) + (unsigned) (k)))
#endif /* CAIRO_MALLOC_PRIVATE_H */

View file

@ -0,0 +1,863 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#define _GNU_SOURCE
#include "cairoint.h"
#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
#define ISFINITE(x) isfinite (x)
#else
#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
#endif
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar);
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix);
/**
* cairo_matrix_init_identity:
* @matrix: a #cairo_matrix_t
*
* Modifies @matrix to be an identity transformation.
**/
void
cairo_matrix_init_identity (cairo_matrix_t *matrix)
{
cairo_matrix_init (matrix,
1, 0,
0, 1,
0, 0);
}
slim_hidden_def(cairo_matrix_init_identity);
/**
* cairo_matrix_init:
* @matrix: a #cairo_matrix_t
* @xx: xx component of the affine transformation
* @yx: yx component of the affine transformation
* @xy: xy component of the affine transformation
* @yy: yy component of the affine transformation
* @x0: X translation component of the affine transformation
* @y0: Y translation component of the affine transformation
*
* Sets @matrix to be the affine transformation given by
* @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given
* by:
* <programlisting>
* x_new = xx * x + xy * y + x0;
* y_new = yx * x + yy * y + y0;
* </programlisting>
**/
void
cairo_matrix_init (cairo_matrix_t *matrix,
double xx, double yx,
double xy, double yy,
double x0, double y0)
{
matrix->xx = xx; matrix->yx = yx;
matrix->xy = xy; matrix->yy = yy;
matrix->x0 = x0; matrix->y0 = y0;
}
slim_hidden_def(cairo_matrix_init);
/**
* _cairo_matrix_get_affine:
* @matrix: a #cairo_matrix_t
* @xx: location to store xx component of matrix
* @yx: location to store yx component of matrix
* @xy: location to store xy component of matrix
* @yy: location to store yy component of matrix
* @x0: location to store x0 (X-translation component) of matrix, or %NULL
* @y0: location to store y0 (Y-translation component) of matrix, or %NULL
*
* Gets the matrix values for the affine transformation that @matrix represents.
* See cairo_matrix_init().
*
*
* This function is a leftover from the old public API, but is still
* mildly useful as an internal means for getting at the matrix
* members in a positional way. For example, when reassigning to some
* external matrix type, or when renaming members to more meaningful
* names (such as a,b,c,d,e,f) for particular manipulations.
**/
void
_cairo_matrix_get_affine (const cairo_matrix_t *matrix,
double *xx, double *yx,
double *xy, double *yy,
double *x0, double *y0)
{
*xx = matrix->xx;
*yx = matrix->yx;
*xy = matrix->xy;
*yy = matrix->yy;
if (x0)
*x0 = matrix->x0;
if (y0)
*y0 = matrix->y0;
}
/**
* cairo_matrix_init_translate:
* @matrix: a #cairo_matrix_t
* @tx: amount to translate in the X direction
* @ty: amount to translate in the Y direction
*
* Initializes @matrix to a transformation that translates by @tx and
* @ty in the X and Y dimensions, respectively.
**/
void
cairo_matrix_init_translate (cairo_matrix_t *matrix,
double tx, double ty)
{
cairo_matrix_init (matrix,
1, 0,
0, 1,
tx, ty);
}
slim_hidden_def(cairo_matrix_init_translate);
/**
* cairo_matrix_translate:
* @matrix: a #cairo_matrix_t
* @tx: amount to translate in the X direction
* @ty: amount to translate in the Y direction
*
* Applies a translation by @tx, @ty to the transformation in
* @matrix. The effect of the new transformation is to first translate
* the coordinates by @tx and @ty, then apply the original transformation
* to the coordinates.
**/
void
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty)
{
cairo_matrix_t tmp;
cairo_matrix_init_translate (&tmp, tx, ty);
cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def (cairo_matrix_translate);
/**
* cairo_matrix_init_scale:
* @matrix: a #cairo_matrix_t
* @sx: scale factor in the X direction
* @sy: scale factor in the Y direction
*
* Initializes @matrix to a transformation that scales by @sx and @sy
* in the X and Y dimensions, respectively.
**/
void
cairo_matrix_init_scale (cairo_matrix_t *matrix,
double sx, double sy)
{
cairo_matrix_init (matrix,
sx, 0,
0, sy,
0, 0);
}
slim_hidden_def(cairo_matrix_init_scale);
/**
* cairo_matrix_scale:
* @matrix: a #cairo_matrix_t
* @sx: scale factor in the X direction
* @sy: scale factor in the Y direction
*
* Applies scaling by @sx, @sy to the transformation in @matrix. The
* effect of the new transformation is to first scale the coordinates
* by @sx and @sy, then apply the original transformation to the coordinates.
**/
void
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy)
{
cairo_matrix_t tmp;
cairo_matrix_init_scale (&tmp, sx, sy);
cairo_matrix_multiply (matrix, &tmp, matrix);
}
slim_hidden_def(cairo_matrix_scale);
/**
* cairo_matrix_init_rotate:
* @matrix: a #cairo_matrix_t
* @radians: angle of rotation, in radians. The direction of rotation
* is defined such that positive angles rotate in the direction from
* the positive X axis toward the positive Y axis. With the default
* axis orientation of cairo, positive angles rotate in a clockwise
* direction.
*
* Initialized @matrix to a transformation that rotates by @radians.
**/
void
cairo_matrix_init_rotate (cairo_matrix_t *matrix,
double radians)
{
double s;
double c;
s = sin (radians);
c = cos (radians);
cairo_matrix_init (matrix,
c, s,
-s, c,
0, 0);
}
slim_hidden_def(cairo_matrix_init_rotate);
/**
* cairo_matrix_rotate:
* @matrix: a #cairo_matrix_t
* @radians: angle of rotation, in radians. The direction of rotation
* is defined such that positive angles rotate in the direction from
* the positive X axis toward the positive Y axis. With the default
* axis orientation of cairo, positive angles rotate in a clockwise
* direction.
*
* Applies rotation by @radians to the transformation in
* @matrix. The effect of the new transformation is to first rotate the
* coordinates by @radians, then apply the original transformation
* to the coordinates.
**/
void
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
{
cairo_matrix_t tmp;
cairo_matrix_init_rotate (&tmp, radians);
cairo_matrix_multiply (matrix, &tmp, matrix);
}
/**
* cairo_matrix_multiply:
* @result: a #cairo_matrix_t in which to store the result
* @a: a #cairo_matrix_t
* @b: a #cairo_matrix_t
*
* Multiplies the affine transformations in @a and @b together
* and stores the result in @result. The effect of the resulting
* transformation is to first apply the transformation in @a to the
* coordinates and then apply the transformation in @b to the
* coordinates.
*
* It is allowable for @result to be identical to either @a or @b.
**/
/*
* XXX: The ordering of the arguments to this function corresponds
* to [row_vector]*A*B. If we want to use column vectors instead,
* then we need to switch the two arguments and fix up all
* uses.
*/
void
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b)
{
cairo_matrix_t r;
r.xx = a->xx * b->xx + a->yx * b->xy;
r.yx = a->xx * b->yx + a->yx * b->yy;
r.xy = a->xy * b->xx + a->yy * b->xy;
r.yy = a->xy * b->yx + a->yy * b->yy;
r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0;
r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0;
*result = r;
}
slim_hidden_def(cairo_matrix_multiply);
/**
* cairo_matrix_transform_distance:
* @matrix: a #cairo_matrix_t
* @dx: X component of a distance vector. An in/out parameter
* @dy: Y component of a distance vector. An in/out parameter
*
* Transforms the distance vector (@dx,@dy) by @matrix. This is
* similar to cairo_matrix_transform_point() except that the translation
* components of the transformation are ignored. The calculation of
* the returned vector is as follows:
*
* <programlisting>
* dx2 = dx1 * a + dy1 * c;
* dy2 = dx1 * b + dy1 * d;
* </programlisting>
*
* Affine transformations are position invariant, so the same vector
* always transforms to the same vector. If (@x1,@y1) transforms
* to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
* (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
**/
void
cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy)
{
double new_x, new_y;
new_x = (matrix->xx * *dx + matrix->xy * *dy);
new_y = (matrix->yx * *dx + matrix->yy * *dy);
*dx = new_x;
*dy = new_y;
}
slim_hidden_def(cairo_matrix_transform_distance);
/**
* cairo_matrix_transform_point:
* @matrix: a #cairo_matrix_t
* @x: X position. An in/out parameter
* @y: Y position. An in/out parameter
*
* Transforms the point (@x, @y) by @matrix.
**/
void
cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y)
{
cairo_matrix_transform_distance (matrix, x, y);
*x += matrix->x0;
*y += matrix->y0;
}
slim_hidden_def(cairo_matrix_transform_point);
void
_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x1, double *y1,
double *x2, double *y2,
cairo_bool_t *is_tight)
{
int i;
double quad_x[4], quad_y[4];
double min_x, max_x;
double min_y, max_y;
quad_x[0] = *x1;
quad_y[0] = *y1;
cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]);
quad_x[1] = *x2;
quad_y[1] = *y1;
cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]);
quad_x[2] = *x1;
quad_y[2] = *y2;
cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]);
quad_x[3] = *x2;
quad_y[3] = *y2;
cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]);
min_x = max_x = quad_x[0];
min_y = max_y = quad_y[0];
for (i=1; i < 4; i++) {
if (quad_x[i] < min_x)
min_x = quad_x[i];
if (quad_x[i] > max_x)
max_x = quad_x[i];
if (quad_y[i] < min_y)
min_y = quad_y[i];
if (quad_y[i] > max_y)
max_y = quad_y[i];
}
*x1 = min_x;
*y1 = min_y;
*x2 = max_x;
*y2 = max_y;
if (is_tight) {
/* it's tight if and only if the four corner points form an axis-aligned
rectangle.
And that's true if and only if we can derive corners 0 and 3 from
corners 1 and 2 in one of two straightforward ways...
We could use a tolerance here but for now we'll fall back to FALSE in the case
of floating point error.
*/
*is_tight =
(quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] &&
quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) ||
(quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] &&
quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]);
}
}
cairo_private void
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
cairo_box_t *bbox,
cairo_bool_t *is_tight)
{
double x1, y1, x2, y2;
_cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
_cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
_cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
matrix->xx *= scalar;
matrix->yx *= scalar;
matrix->xy *= scalar;
matrix->yy *= scalar;
matrix->x0 *= scalar;
matrix->y0 *= scalar;
}
/* This function isn't a correct adjoint in that the implicit 1 in the
homogeneous result should actually be ad-bc instead. But, since this
adjoint is only used in the computation of the inverse, which
divides by det (A)=ad-bc anyway, everything works out in the end. */
static void
_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix)
{
/* adj (A) = transpose (C:cofactor (A,i,j)) */
double a, b, c, d, tx, ty;
_cairo_matrix_get_affine (matrix,
&a, &b,
&c, &d,
&tx, &ty);
cairo_matrix_init (matrix,
d, -b,
-c, a,
c*ty - d*tx, b*tx - a*ty);
}
/**
* cairo_matrix_invert:
* @matrix: a #cairo_matrix_t
*
* Changes @matrix to be the inverse of it's original value. Not
* all transformation matrices have inverses; if the matrix
* collapses points together (it is <firstterm>degenerate</firstterm>),
* then it has no inverse and this function will fail.
*
* Returns: If @matrix has an inverse, modifies @matrix to
* be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise,
* returns %CAIRO_STATUS_INVALID_MATRIX.
**/
cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix)
{
/* inv (A) = 1/det (A) * adj (A) */
double det;
det = _cairo_matrix_compute_determinant (matrix);
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (det == 0)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_matrix_compute_adjoint (matrix);
_cairo_matrix_scalar_multiply (matrix, 1 / det);
return CAIRO_STATUS_SUCCESS;
}
slim_hidden_def(cairo_matrix_invert);
cairo_bool_t
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
{
double det;
det = _cairo_matrix_compute_determinant (matrix);
return ISFINITE (det) && det != 0.;
}
double
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix)
{
double a, b, c, d;
a = matrix->xx; b = matrix->yx;
c = matrix->xy; d = matrix->yy;
return a*d - b*c;
}
/**
* _cairo_matrix_compute_basis_scale_factors:
* @matrix: a matrix
* @basis_scale: the scale factor in the direction of basis
* @normal_scale: the scale factor in the direction normal to the basis
* @x_basis: basis to use. X basis if true, Y basis otherwise.
*
* Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1]
* otherwise, and M is @matrix.
*
* Return value: the scale factor of @matrix on the height of the font,
* or 1.0 if @matrix is %NULL.
**/
cairo_status_t
_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix,
double *basis_scale, double *normal_scale,
cairo_bool_t x_basis)
{
double det;
det = _cairo_matrix_compute_determinant (matrix);
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (det == 0)
{
*basis_scale = *normal_scale = 0;
}
else
{
double x = x_basis != 0;
double y = x == 0;
double major, minor;
cairo_matrix_transform_distance (matrix, &x, &y);
major = sqrt(x*x + y*y);
/*
* ignore mirroring
*/
if (det < 0)
det = -det;
if (major)
minor = det / major;
else
minor = 0.0;
if (x_basis)
{
*basis_scale = major;
*normal_scale = minor;
}
else
{
*basis_scale = minor;
*normal_scale = major;
}
}
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_matrix_is_identity (const cairo_matrix_t *matrix)
{
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
matrix->xy == 0.0 && matrix->yy == 1.0 &&
matrix->x0 == 0.0 && matrix->y0 == 0.0);
}
cairo_bool_t
_cairo_matrix_is_translation (const cairo_matrix_t *matrix)
{
return (matrix->xx == 1.0 && matrix->yx == 0.0 &&
matrix->xy == 0.0 && matrix->yy == 1.0);
}
cairo_bool_t
_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
int *itx, int *ity)
{
if (_cairo_matrix_is_translation (matrix))
{
cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);
if (_cairo_fixed_is_integer (x0_fixed) &&
_cairo_fixed_is_integer (y0_fixed))
{
if (itx)
*itx = _cairo_fixed_integer_part (x0_fixed);
if (ity)
*ity = _cairo_fixed_integer_part (y0_fixed);
return TRUE;
}
}
return FALSE;
}
/* By pixel exact here, we mean a matrix that is composed only of
* 90 degree rotations, flips, and integer translations and produces a 1:1
* mapping between source and destination pixels. If we transform an image
* with a pixel-exact matrix, filtering is not useful.
*/
cairo_private cairo_bool_t
_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix)
{
cairo_fixed_t x0_fixed, y0_fixed;
if (matrix->xy == 0.0 && matrix->yx == 0.0) {
if (! (matrix->xx == 1.0 || matrix->xx == -1.0))
return FALSE;
if (! (matrix->yy == 1.0 || matrix->yy == -1.0))
return FALSE;
} else if (matrix->xx == 0.0 && matrix->yy == 0.0) {
if (! (matrix->xy == 1.0 || matrix->xy == -1.0))
return FALSE;
if (! (matrix->yx == 1.0 || matrix->yx == -1.0))
return FALSE;
} else
return FALSE;
x0_fixed = _cairo_fixed_from_double (matrix->x0);
y0_fixed = _cairo_fixed_from_double (matrix->y0);
return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed);
}
/*
A circle in user space is transformed into an ellipse in device space.
The following is a derivation of a formula to calculate the length of the
major axis for this ellipse; this is useful for error bounds calculations.
Thanks to Walter Brisken <wbrisken@aoc.nrao.edu> for this derivation:
1. First some notation:
All capital letters represent vectors in two dimensions. A prime '
represents a transformed coordinate. Matrices are written in underlined
form, ie _R_. Lowercase letters represent scalar real values.
2. The question has been posed: What is the maximum expansion factor
achieved by the linear transformation
X' = X _R_
where _R_ is a real-valued 2x2 matrix with entries:
_R_ = [a b]
[c d] .
In other words, what is the maximum radius, MAX[ |X'| ], reached for any
X on the unit circle ( |X| = 1 ) ?
3. Some useful formulae
(A) through (C) below are standard double-angle formulae. (D) is a lesser
known result and is derived below:
(A) sin²(θ) = (1 - cos(2*θ))/2
(B) cos²(θ) = (1 + cos(2*θ))/2
(C) sin(θ)*cos(θ) = sin(2*θ)/2
(D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²)
Proof of (D):
find the maximum of the function by setting the derivative to zero:
-a*sin(θ)+b*cos(θ) = 0
From this it follows that
tan(θ) = b/a
and hence
sin(θ) = b/sqrt(a² + b²)
and
cos(θ) = a/sqrt(a² + b²)
Thus the maximum value is
MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²)
= sqrt(a² + b²)
4. Derivation of maximum expansion
To find MAX[ |X'| ] we search brute force method using calculus. The unit
circle on which X is constrained is to be parameterized by t:
X(θ) = (cos(θ), sin(θ))
Thus
X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b]
[c d]
= (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)).
Define
r(θ) = |X'(θ)|
Thus
r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))²
= (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ)
+ 2*(a*c + b*d)*cos(θ)*sin(θ)
Now apply the double angle formulae (A) to (C) from above:
r²(θ) = (a² + b² + c² + d²)/2
+ (a² + b² - c² - d²)*cos(2*θ)/2
+ (a*c + b*d)*sin(2*θ)
= f + g*cos(φ) + h*sin(φ)
Where
f = (a² + b² + c² + d²)/2
g = (a² + b² - c² - d²)/2
h = (a*c + d*d)
φ = 2*θ
It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ]
using (D) from above:
MAX[ r² ] = f + sqrt(g² + h²)
And finally
MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) )
Which is the solution to this problem.
Walter Brisken
2004/10/08
(Note that the minor axis length is at the minimum of the above solution,
which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
For another derivation of the same result, using Singular Value Decomposition,
see doc/tutorial/src/singular.c.
*/
/* determine the length of the major axis of a circle of the given radius
after applying the transformation matrix. */
double
_cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radius)
{
double a, b, c, d, f, g, h, i, j;
_cairo_matrix_get_affine (matrix,
&a, &b,
&c, &d,
NULL, NULL);
i = a*a + b*b;
j = c*c + d*d;
f = 0.5 * (i + j);
g = 0.5 * (i - j);
h = a*c + b*d;
return radius * sqrt (f + sqrt (g*g+h*h));
/*
* we don't need the minor axis length, which is
* double min = radius * sqrt (f - sqrt (g*g+h*h));
*/
}
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
pixman_transform_t *pixman_transform)
{
static const pixman_transform_t pixman_identity_transform = {{
{1 << 16, 0, 0},
{ 0, 1 << 16, 0},
{ 0, 0, 1 << 16}
}};
if (_cairo_matrix_is_identity (matrix)) {
*pixman_transform = pixman_identity_transform;
}
else {
cairo_matrix_t inv = *matrix;
double x = 0, y = 0;
pixman_vector_t vector;
pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
pixman_transform->matrix[2][0] = 0;
pixman_transform->matrix[2][1] = 0;
pixman_transform->matrix[2][2] = 1 << 16;
/* The conversion above breaks cairo's translation invariance:
* a translation of (a, b) in device space translates to
* a translation of (xx * a + xy * b, yx * a + yy * b)
* for cairo, while pixman uses rounded versions of xx ... yy.
* This error increases as a and b get larger.
*
* To compensate for this, we fix the point (0, 0) in pattern
* space and adjust pixman's transform to agree with cairo's at
* that point. */
/* Note: If we can't invert the transformation, skip the adjustment. */
if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
return;
/* find the device space coordinate that maps to (0, 0) */
cairo_matrix_transform_point (&inv, &x, &y);
/* transform the resulting device space coordinate back
* to the pattern space, using pixman's transform */
vector.vector[0] = _cairo_fixed_16_16_from_double (x);
vector.vector[1] = _cairo_fixed_16_16_from_double (y);
vector.vector[2] = 1 << 16;
if (!pixman_transform_point_3d (pixman_transform, &vector))
return;
/* Ideally, the vector should now be (0, 0). We can now compensate
* for the resulting error */
pixman_transform->matrix[0][2] -= vector.vector[0];
pixman_transform->matrix[1][2] -= vector.vector[1];
}
}

View file

@ -0,0 +1,190 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
#ifndef CAIRO_META_SURFACE_H
#define CAIRO_META_SURFACE_H
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
typedef enum {
/* The 5 basic drawing operations. */
CAIRO_COMMAND_PAINT,
CAIRO_COMMAND_MASK,
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
/* Other junk. For most of these, we should be able to assert that
* they never get called except as part of fallbacks for the 5
* basic drawing operations (which we implement already so the
* fallbacks should never get triggered). So the plan is to
* eliminate as many of these as possible. */
CAIRO_COMMAND_INTERSECT_CLIP_PATH
} cairo_command_type_t;
typedef enum {
CAIRO_META_REGION_ALL,
CAIRO_META_REGION_NATIVE,
CAIRO_META_REGION_IMAGE_FALLBACK
} cairo_meta_region_type_t;
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_meta_region_type_t region;
} cairo_command_header_t;
typedef struct _cairo_command_paint {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
} cairo_command_paint_t;
typedef struct _cairo_command_mask {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_pattern_union_t mask;
} cairo_command_mask_t;
typedef struct _cairo_command_stroke {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_stroke_style_t style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_stroke_t;
typedef struct _cairo_command_fill {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_fill_t;
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
unsigned int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_text_cluster_flags_t cluster_flags;
cairo_scaled_font_t *scaled_font;
} cairo_command_show_text_glyphs_t;
typedef struct _cairo_command_intersect_clip_path {
cairo_command_header_t header;
cairo_path_fixed_t *path_pointer;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
double tolerance;
cairo_antialias_t antialias;
} cairo_command_intersect_clip_path_t;
typedef union _cairo_command {
cairo_command_header_t header;
/* The 5 basic drawing operations. */
cairo_command_paint_t paint;
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_text_glyphs_t show_text_glyphs;
/* The other junk. */
cairo_command_intersect_clip_path_t intersect_clip_path;
} cairo_command_t;
typedef struct _cairo_meta_surface {
cairo_surface_t base;
cairo_content_t content;
/* A meta-surface is logically unbounded, but when used as a
* source we need to render it to an image, so we need a size at
* which to create that image. */
int width_pixels;
int height_pixels;
cairo_array_t commands;
cairo_surface_t *commands_owner;
cairo_bool_t is_clipped;
int replay_start_idx;
} cairo_meta_surface_t;
cairo_private cairo_surface_t *
_cairo_meta_surface_create (cairo_content_t content,
int width_pixels,
int height_pixels);
cairo_private cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_meta_surface_replay_analyze_meta_pattern (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_meta_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_meta_surface_replay_region (cairo_surface_t *surface,
cairo_surface_t *target,
cairo_meta_region_type_t region);
cairo_private cairo_bool_t
_cairo_surface_is_meta (const cairo_surface_t *surface);
#endif /* CAIRO_META_SURFACE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,669 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
#include "cairoint.h"
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
/* Public stuff */
/**
* cairo_status_to_string:
* @status: a cairo status
*
* Provides a human-readable description of a #cairo_status_t.
*
* Returns: a string representation of the status
*/
const char *
cairo_status_to_string (cairo_status_t status)
{
switch (status) {
case CAIRO_STATUS_SUCCESS:
return "success";
case CAIRO_STATUS_NO_MEMORY:
return "out of memory";
case CAIRO_STATUS_INVALID_RESTORE:
return "cairo_restore without matching cairo_save";
case CAIRO_STATUS_INVALID_POP_GROUP:
return "cairo_pop_group without matching cairo_push_group";
case CAIRO_STATUS_NO_CURRENT_POINT:
return "no current point defined";
case CAIRO_STATUS_INVALID_MATRIX:
return "invalid matrix (not invertible)";
case CAIRO_STATUS_INVALID_STATUS:
return "invalid value for an input cairo_status_t";
case CAIRO_STATUS_NULL_POINTER:
return "NULL pointer";
case CAIRO_STATUS_INVALID_STRING:
return "input string not valid UTF-8";
case CAIRO_STATUS_INVALID_PATH_DATA:
return "input path data not valid";
case CAIRO_STATUS_READ_ERROR:
return "error while reading from input stream";
case CAIRO_STATUS_WRITE_ERROR:
return "error while writing to output stream";
case CAIRO_STATUS_SURFACE_FINISHED:
return "the target surface has been finished";
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
return "the surface type is not appropriate for the operation";
case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
return "the pattern type is not appropriate for the operation";
case CAIRO_STATUS_INVALID_CONTENT:
return "invalid value for an input cairo_content_t";
case CAIRO_STATUS_INVALID_FORMAT:
return "invalid value for an input cairo_format_t";
case CAIRO_STATUS_INVALID_VISUAL:
return "invalid value for an input Visual*";
case CAIRO_STATUS_FILE_NOT_FOUND:
return "file not found";
case CAIRO_STATUS_INVALID_DASH:
return "invalid value for a dash setting";
case CAIRO_STATUS_INVALID_DSC_COMMENT:
return "invalid value for a DSC comment";
case CAIRO_STATUS_INVALID_INDEX:
return "invalid index passed to getter";
case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
return "clip region not representable in desired format";
case CAIRO_STATUS_TEMP_FILE_ERROR:
return "error creating or writing to a temporary file";
case CAIRO_STATUS_INVALID_STRIDE:
return "invalid value for stride";
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
return "the font type is not appropriate for the operation";
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
return "the user-font is immutable";
case CAIRO_STATUS_USER_FONT_ERROR:
return "error occurred in a user-font callback function";
case CAIRO_STATUS_NEGATIVE_COUNT:
return "negative number used where it is not allowed";
case CAIRO_STATUS_INVALID_CLUSTERS:
return "input clusters do not represent the accompanying text and glyph arrays";
case CAIRO_STATUS_INVALID_SLANT:
return "invalid value for an input #cairo_font_slant_t";
case CAIRO_STATUS_INVALID_WEIGHT:
return "input value for an input #cairo_font_weight_t";
}
return "<unknown error status>";
}
/**
* cairo_glyph_allocate:
* @num_glyphs: number of glyphs to allocate
*
* Allocates an array of #cairo_glyph_t's.
* This function is only useful in implementations of
* #cairo_user_scaled_font_text_to_glyphs_func_t where the user
* needs to allocate an array of glyphs that cairo will free.
* For all other uses, user can use their own allocation method
* for glyphs.
*
* This function returns %NULL if @num_glyphs is not positive,
* or if out of memory. That means, the %NULL return value
* signals out-of-memory only if @num_glyphs was positive.
*
* Returns: the newly allocated array of glyphs that should be
* freed using cairo_glyph_free()
*
* Since: 1.8
*/
cairo_glyph_t *
cairo_glyph_allocate (int num_glyphs)
{
if (num_glyphs <= 0)
return NULL;
return _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
}
slim_hidden_def (cairo_glyph_allocate);
/**
* cairo_glyph_free:
* @glyphs: array of glyphs to free, or %NULL
*
* Frees an array of #cairo_glyph_t's allocated using cairo_glyph_allocate().
* This function is only useful to free glyph array returned
* by cairo_scaled_font_text_to_glyphs() where cairo returns
* an array of glyphs that the user will free.
* For all other uses, user can use their own allocation method
* for glyphs.
*
* Since: 1.8
*/
void
cairo_glyph_free (cairo_glyph_t *glyphs)
{
if (glyphs)
free (glyphs);
}
slim_hidden_def (cairo_glyph_free);
/**
* cairo_text_cluster_allocate:
* @num_clusters: number of text_clusters to allocate
*
* Allocates an array of #cairo_text_cluster_t's.
* This function is only useful in implementations of
* #cairo_user_scaled_font_text_to_glyphs_func_t where the user
* needs to allocate an array of text clusters that cairo will free.
* For all other uses, user can use their own allocation method
* for text clusters.
*
* This function returns %NULL if @num_clusters is not positive,
* or if out of memory. That means, the %NULL return value
* signals out-of-memory only if @num_clusters was positive.
*
* Returns: the newly allocated array of text clusters that should be
* freed using cairo_text_cluster_free()
*
* Since: 1.8
*/
cairo_text_cluster_t *
cairo_text_cluster_allocate (int num_clusters)
{
if (num_clusters <= 0)
return NULL;
return _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
}
slim_hidden_def (cairo_text_cluster_allocate);
/**
* cairo_text_cluster_free:
* @clusters: array of text clusters to free, or %NULL
*
* Frees an array of #cairo_text_cluster's allocated using cairo_text_cluster_allocate().
* This function is only useful to free text cluster array returned
* by cairo_scaled_font_text_to_glyphs() where cairo returns
* an array of text clusters that the user will free.
* For all other uses, user can use their own allocation method
* for text clusters.
*
* Since: 1.8
*/
void
cairo_text_cluster_free (cairo_text_cluster_t *clusters)
{
if (clusters)
free (clusters);
}
slim_hidden_def (cairo_text_cluster_free);
/* Private stuff */
/**
* _cairo_validate_text_clusters:
* @utf8: UTF-8 text
* @utf8_len: length of @utf8 in bytes
* @glyphs: array of glyphs
* @num_glyphs: number of glyphs
* @clusters: array of cluster mapping information
* @num_clusters: number of clusters in the mapping
* @cluster_flags: cluster flags
*
* Check that clusters cover the entire glyphs and utf8 arrays,
* and that cluster boundaries are UTF-8 boundaries.
*
* Return value: %CAIRO_STATUS_SUCCESS upon success, or
* %CAIRO_STATUS_INVALID_CLUSTERS on error.
* The error is either invalid UTF-8 input,
* or bad cluster mapping.
*/
cairo_status_t
_cairo_validate_text_clusters (const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags)
{
cairo_status_t status;
unsigned int n_bytes = 0;
unsigned int n_glyphs = 0;
int i;
for (i = 0; i < num_clusters; i++) {
int cluster_bytes = clusters[i].num_bytes;
int cluster_glyphs = clusters[i].num_glyphs;
if (cluster_bytes < 0 || cluster_glyphs < 0)
goto BAD;
/* A cluster should cover at least one character or glyph.
* I can't see any use for a 0,0 cluster.
* I can't see an immediate use for a zero-text cluster
* right now either, but they don't harm.
* Zero-glyph clusters on the other hand are useful for
* things like U+200C ZERO WIDTH NON-JOINER */
if (cluster_bytes == 0 && cluster_glyphs == 0)
goto BAD;
/* Since n_bytes and n_glyphs are unsigned, but the rest of
* values involved are signed, we can detect overflow easily */
if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs)
goto BAD;
/* Make sure we've got valid UTF-8 for the cluster */
status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL);
if (status)
return CAIRO_STATUS_INVALID_CLUSTERS;
n_bytes += cluster_bytes ;
n_glyphs += cluster_glyphs;
}
if (n_bytes != (unsigned int) utf8_len || n_glyphs != (unsigned int) num_glyphs) {
BAD:
return CAIRO_STATUS_INVALID_CLUSTERS;
}
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_operator_bounded_by_mask:
* @op: a #cairo_operator_t
*
* A bounded operator is one where mask pixel
* of zero results in no effect on the destination image.
*
* Unbounded operators often require special handling; if you, for
* example, draw trapezoids with an unbounded operator, the effect
* extends past the bounding box of the trapezoids.
*
* Return value: %TRUE if the operator is bounded by the mask operand
**/
cairo_bool_t
_cairo_operator_bounded_by_mask (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
return TRUE;
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return FALSE;
}
ASSERT_NOT_REACHED;
return FALSE;
}
/**
* _cairo_operator_bounded_by_source:
* @op: a #cairo_operator_t
*
* A bounded operator is one where source pixels of zero
* (in all four components, r, g, b and a) effect no change
* in the resulting destination image.
*
* Unbounded operators often require special handling; if you, for
* example, copy a surface with the SOURCE operator, the effect
* extends past the bounding box of the source surface.
*
* Return value: %TRUE if the operator is bounded by the source operand
**/
cairo_bool_t
_cairo_operator_bounded_by_source (cairo_operator_t op)
{
switch (op) {
case CAIRO_OPERATOR_OVER:
case CAIRO_OPERATOR_ATOP:
case CAIRO_OPERATOR_DEST:
case CAIRO_OPERATOR_DEST_OVER:
case CAIRO_OPERATOR_DEST_OUT:
case CAIRO_OPERATOR_XOR:
case CAIRO_OPERATOR_ADD:
case CAIRO_OPERATOR_SATURATE:
return TRUE;
case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE:
case CAIRO_OPERATOR_OUT:
case CAIRO_OPERATOR_IN:
case CAIRO_OPERATOR_DEST_IN:
case CAIRO_OPERATOR_DEST_ATOP:
return FALSE;
}
ASSERT_NOT_REACHED;
return FALSE;
}
void
_cairo_restrict_value (double *value, double min, double max)
{
if (*value < min)
*value = min;
else if (*value > max)
*value = max;
}
/* This function is identical to the C99 function lround(), except that it
* performs arithmetic rounding (instead of away-from-zero rounding) and
* has a valid input range of (INT_MIN, INT_MAX] instead of
* [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems
* than other commonly used methods for rounding (lround, round, rint, lrint
* or float (d + 0.5)).
*
* The reason why this function is much faster on x86 than other
* methods is due to the fact that it avoids the fldcw instruction.
* This instruction incurs a large performance penalty on modern Intel
* processors due to how it prevents efficient instruction pipelining.
*
* The reason why this function is much faster on FPU-less systems is for
* an entirely different reason. All common rounding methods involve multiple
* floating-point operations. Each one of these operations has to be
* emulated in software, which adds up to be a large performance penalty.
* This function doesn't perform any floating-point calculations, and thus
* avoids this penalty.
*/
int
_cairo_lround (double d)
{
uint32_t top, shift_amount, output;
union {
double d;
uint64_t ui64;
uint32_t ui32[2];
} u;
u.d = d;
/* If the integer word order doesn't match the float word order, we swap
* the words of the input double. This is needed because we will be
* treating the whole double as a 64-bit unsigned integer. Notice that we
* use WORDS_BIGENDIAN to detect the integer word order, which isn't
* exactly correct because WORDS_BIGENDIAN refers to byte order, not word
* order. Thus, we are making the assumption that the byte order is the
* same as the integer word order which, on the modern machines that we
* care about, is OK.
*/
#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \
(!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN))
{
uint32_t temp = u.ui32[0];
u.ui32[0] = u.ui32[1];
u.ui32[1] = temp;
}
#endif
#ifdef WORDS_BIGENDIAN
#define MSW (0) /* Most Significant Word */
#define LSW (1) /* Least Significant Word */
#else
#define MSW (1)
#define LSW (0)
#endif
/* By shifting the most significant word of the input double to the
* right 20 places, we get the very "top" of the double where the exponent
* and sign bit lie.
*/
top = u.ui32[MSW] >> 20;
/* Here, we calculate how much we have to shift the mantissa to normalize
* it to an integer value. We extract the exponent "top" by masking out the
* sign bit, then we calculate the shift amount by subtracting the exponent
* from the bias. Notice that the correct bias for 64-bit doubles is
* actually 1075, but we use 1053 instead for two reasons:
*
* 1) To perform rounding later on, we will first need the target
* value in a 31.1 fixed-point format. Thus, the bias needs to be one
* less: (1075 - 1: 1074).
*
* 2) To avoid shifting the mantissa as a full 64-bit integer (which is
* costly on certain architectures), we break the shift into two parts.
* First, the upper and lower parts of the mantissa are shifted
* individually by a constant amount that all valid inputs will require
* at the very least. This amount is chosen to be 21, because this will
* allow the two parts of the mantissa to later be combined into a
* single 32-bit representation, on which the remainder of the shift
* will be performed. Thus, we decrease the bias by an additional 21:
* (1074 - 21: 1053).
*/
shift_amount = 1053 - (top & 0x7FF);
/* We are done with the exponent portion in "top", so here we shift it off
* the end.
*/
top >>= 11;
/* Before we perform any operations on the mantissa, we need to OR in
* the implicit 1 at the top (see the IEEE-754 spec). We needn't mask
* off the sign bit nor the exponent bits because these higher bits won't
* make a bit of difference in the rest of our calculations.
*/
u.ui32[MSW] |= 0x100000;
/* If the input double is negative, we have to decrease the mantissa
* by a hair. This is an important part of performing arithmetic rounding,
* as negative numbers must round towards positive infinity in the
* halfwase case of -x.5. Since "top" contains only the sign bit at this
* point, we can just decrease the mantissa by the value of "top".
*/
u.ui64 -= top;
/* By decrementing "top", we create a bitmask with a value of either
* 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive
* and thus the unsigned subtraction underflowed) that we'll use later.
*/
top--;
/* Here, we shift the mantissa by the constant value as described above.
* We can emulate a 64-bit shift right by 21 through shifting the top 32
* bits left 11 places and ORing in the bottom 32 bits shifted 21 places
* to the right. Both parts of the mantissa are now packed into a single
* 32-bit integer. Although we severely truncate the lower part in the
* process, we still have enough significant bits to perform the conversion
* without error (for all valid inputs).
*/
output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21);
/* Next, we perform the shift that converts the X.Y fixed-point number
* currently found in "output" to the desired 31.1 fixed-point format
* needed for the following rounding step. It is important to consider
* all possible values for "shift_amount" at this point:
*
* - {shift_amount < 0} Since shift_amount is an unsigned integer, it
* really can't have a value less than zero. But, if the shift_amount
* calculation above caused underflow (which would happen with
* input > INT_MAX or input <= INT_MIN) then shift_amount will now be
* a very large number, and so this shift will result in complete
* garbage. But that's OK, as the input was out of our range, so our
* output is undefined.
*
* - {shift_amount > 31} If the magnitude of the input was very small
* (i.e. |input| << 1.0), shift_amount will have a value greater than
* 31. Thus, this shift will also result in garbage. After performing
* the shift, we will zero-out "output" if this is the case.
*
* - {0 <= shift_amount < 32} In this case, the shift will properly convert
* the mantissa into a 31.1 fixed-point number.
*/
output >>= shift_amount;
/* This is where we perform rounding with the 31.1 fixed-point number.
* Since what we're after is arithmetic rounding, we simply add the single
* fractional bit into the integer part of "output", and just keep the
* integer part.
*/
output = (output >> 1) + (output & 1);
/* Here, we zero-out the result if the magnitude if the input was very small
* (as explained in the section above). Notice that all input out of the
* valid range is also caught by this condition, which means we produce 0
* for all invalid input, which is a nice side effect.
*
* The most straightforward way to do this would be:
*
* if (shift_amount > 31)
* output = 0;
*
* But we can use a little trick to avoid the potential branch. The
* expression (shift_amount > 31) will be either 1 or 0, which when
* decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow),
* which can be used to conditionally mask away all the bits in "output"
* (in the 0x0 case), effectively zeroing it out. Certain, compilers would
* have done this for us automatically.
*/
output &= ((shift_amount > 31) - 1);
/* If the input double was a negative number, then we have to negate our
* output. The most straightforward way to do this would be:
*
* if (!top)
* output = -output;
*
* as "top" at this point is either 0x0 (if the input was negative) or
* 0xFFFFFFFF (if the input was positive). But, we can use a trick to
* avoid the branch. Observe that the following snippet of code has the
* same effect as the reference snippet above:
*
* if (!top)
* output = 0 - output;
* else
* output = output - 0;
*
* Armed with the bitmask found in "top", we can condense the two statements
* into the following:
*
* output = (output & top) - (output & ~top);
*
* where, in the case that the input double was negative, "top" will be 0,
* and the statement will be equivalent to:
*
* output = (0) - (output);
*
* and if the input double was positive, "top" will be 0xFFFFFFFF, and the
* statement will be equivalent to:
*
* output = (output) - (0);
*
* Which, as pointed out earlier, is equivalent to the original reference
* snippet.
*/
output = (output & top) - (output & ~top);
return output;
#undef MSW
#undef LSW
}
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
/* We require Windows 2000 features such as ETO_PDY */
#if !defined(WINVER) || (WINVER < 0x0500)
# define WINVER 0x0500
#endif
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
# define _WIN32_WINNT 0x0500
#endif
#include <windows.h>
#include <io.h>
/* tmpfile() replacment for Windows.
*
* On Windows tmpfile() creates the file in the root directory. This
* may fail due to unsufficient privileges.
*/
FILE *
_cairo_win32_tmpfile (void)
{
DWORD path_len;
WCHAR path_name[MAX_PATH + 1];
WCHAR file_name[MAX_PATH + 1];
HANDLE handle;
int fd;
FILE *fp;
path_len = GetTempPathW (MAX_PATH, path_name);
if (path_len <= 0 || path_len >= MAX_PATH)
return NULL;
if (GetTempFileNameW (path_name, L"ps_", 0, file_name) == 0)
return NULL;
handle = CreateFileW (file_name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
DeleteFileW (file_name);
return NULL;
}
fd = _open_osfhandle((intptr_t) handle, 0);
if (fd < 0) {
CloseHandle (handle);
return NULL;
}
fp = fdopen(fd, "w+b");
if (fp == NULL) {
_close(fd);
return NULL;
}
return fp;
}
#endif /* _WIN32 */

View file

@ -0,0 +1,239 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H
#define CAIRO_MUTEX_IMPL_PRIVATE_H
#include "cairo.h"
#if HAVE_CONFIG_H
#include "config.h"
#endif
#if HAVE_LOCKDEP
#include <lockdep.h>
#endif
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_IMPL_NOOP do {/*no-op*/} while (0)
/* And one that evaluates it's argument once */
#define CAIRO_MUTEX_IMPL_NOOP1(expr) do { if (expr) ; } while (0)
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_impl_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_<NAME> 1 with suitable name for your platform. You
* can later use this symbol in cairo-system.c.
*
* - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_impl_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex);
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_impl_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
#if CAIRO_NO_MUTEX
/* No mutexes */
typedef int cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_NO 1
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_PTHREAD 1
#if HAVE_LOCKDEP
/* expose all mutexes to the validator */
# define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL)
#endif
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
#if HAVE_LOCKDEP
# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex))
# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex))
#endif
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
#if ! HAVE_LOCKDEP
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
#endif
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif defined(HAVE_WINDOWS_H) || defined(_MSC_VER) /*************************/
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_WIN32 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
#elif defined __OS2__ /******************************************************/
# define INCL_BASE
# define INCL_PM
# include <os2.h>
typedef HMTX cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_OS2 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_IMPL_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_IMPL_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
typedef BLocker* cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_BEOS 1
# define CAIRO_MUTEX_IMPL_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_IMPL_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#endif
#endif

View file

@ -0,0 +1,59 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
*/
#ifndef CAIRO_FEATURES_H
/* This block is to just make this header file standalone */
#define CAIRO_MUTEX_DECLARE(mutex)
#endif
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock)
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
#if CAIRO_HAS_FT_FONT
CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
#endif
#if CAIRO_HAS_XLIB_SURFACE
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
#endif
#if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER)
CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex)
#endif
/* Undefine, to err on unintended inclusion */
#undef CAIRO_MUTEX_DECLARE

View file

@ -0,0 +1,67 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_MUTEX_PRIVATE_H
#define CAIRO_MUTEX_PRIVATE_H
#include "cairo-mutex-type-private.h"
CAIRO_BEGIN_DECLS
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
cairo_private void _cairo_mutex_initialize (void);
#endif
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private void _cairo_mutex_finalize (void);
#endif
/* only if using static initializer and/or finalizer define the boolean */
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private extern cairo_bool_t _cairo_mutex_initialized;
#endif
/* Finally, extern the static mutexes and undef */
#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex;
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
CAIRO_END_DECLS
#endif

View file

@ -0,0 +1,187 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
#define CAIRO_MUTEX_TYPE_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
/* Only the following three are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#ifdef CAIRO_MUTEX_IMPL_INIT
/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
#else /* no CAIRO_MUTEX_IMPL_INIT */
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_IMPL_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
#endif /* CAIRO_MUTEX_IMPL_INIT */
#ifdef CAIRO_MUTEX_IMPL_FINI
/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
#else /* no CAIRO_MUTEX_IMPL_FINI */
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
#endif /* CAIRO_MUTEX_IMPL_FINI */
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0
#endif
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0
#endif
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINALIZE
# error "CAIRO_MUTEX_IMPL_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_INIT
# error "CAIRO_MUTEX_IMPL_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINI
# error "CAIRO_MUTEX_IMPL_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined"
#endif
/* Public interface. */
/* By default it simply uses the implementation provided.
* But we can provide for debugging features by overriding them */
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
#define CAIRO_MUTEX_INITIALIZE CAIRO_MUTEX_IMPL_INITIALIZE
#define CAIRO_MUTEX_FINALIZE CAIRO_MUTEX_IMPL_FINALIZE
#define CAIRO_MUTEX_LOCK CAIRO_MUTEX_IMPL_LOCK
#define CAIRO_MUTEX_UNLOCK CAIRO_MUTEX_IMPL_UNLOCK
#define CAIRO_MUTEX_INIT CAIRO_MUTEX_IMPL_INIT
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
#ifndef CAIRO_MUTEX_IS_LOCKED
# define CAIRO_MUTEX_IS_LOCKED(name) 1
#endif
#ifndef CAIRO_MUTEX_IS_UNLOCKED
# define CAIRO_MUTEX_IS_UNLOCKED(name) 1
#endif
/* Debugging support */
#ifdef CAIRO_MUTEX_DEBUG
/* TODO add mutex debugging facilities here (eg deadlock detection) */
#endif /* CAIRO_MUTEX_DEBUG */
#endif

View file

@ -0,0 +1,82 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
*/
#include "cairoint.h"
#include "cairo-mutex-private.h"
#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER;
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE FALSE
# else
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE TRUE
# endif
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE;
# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE
#endif
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
void _cairo_mutex_initialize (void)
{
if (_cairo_mutex_initialized)
return;
_cairo_mutex_initialized = TRUE;
#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex);
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
}
#endif
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
void _cairo_mutex_finalize (void)
{
if (!_cairo_mutex_initialized)
return;
_cairo_mutex_initialized = FALSE;
#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex);
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
}
#endif

View file

@ -0,0 +1,77 @@
/* vim: set sw=4 sts=4 et cin: */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2005-2006 netlabs.org
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is
* Doodle <doodle@scenergy.dfmk.hu>
*
* Contributor(s):
* Peter Weilbacher <mozilla@Weilbacher.org>
*/
#ifndef CAIRO_OS2_PRIVATE_H
#define CAIRO_OS2_PRIVATE_H
#include "cairo-os2.h"
#include "cairoint.h"
#define INCL_DOS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS
#define INCL_WIN
#define INCL_GPI
#ifdef __WATCOMC__
# include <os2.h>
#else
# include <os2emx.h>
#endif
typedef struct _cairo_os2_surface
{
cairo_surface_t base;
/* Mutex semaphore to protect private fields from concurrent access */
HMTX hmtx_use_private_fields;
/* Private fields: */
HPS hps_client_window;
HWND hwnd_client_window;
BITMAPINFO2 bitmap_info;
unsigned char *pixels;
cairo_image_surface_t *image_surface;
int pixel_array_lend_count;
HEV hev_pixel_array_came_back;
RECTL rcl_dirty_area;
cairo_bool_t dirty_area_present;
/* General flags: */
cairo_bool_t blit_as_changes;
} cairo_os2_surface_t;
#endif /* CAIRO_OS2_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,88 @@
/* vim: set sw=4 sts=4 et cin: */
/* cairo - a vector graphics library with display and print output
*
* Copyright (c) 2005-2006 netlabs.org
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is
* Doodle <doodle@scenergy.dfmk.hu>
*
* Contributor(s):
* Peter Weilbacher <mozilla@Weilbacher.org>
*/
#ifndef _CAIRO_OS2_H_
#define _CAIRO_OS2_H_
#include "cairo.h"
CAIRO_BEGIN_DECLS
/* The OS/2 Specific Cairo API */
cairo_public void
cairo_os2_init (void);
cairo_public void
cairo_os2_fini (void);
#if CAIRO_HAS_OS2_SURFACE
cairo_public cairo_surface_t *
cairo_os2_surface_create (HPS hps_client_window,
int width,
int height);
cairo_public void
cairo_os2_surface_set_hwnd (cairo_surface_t *surface,
HWND hwnd_client_window);
cairo_public int
cairo_os2_surface_set_size (cairo_surface_t *surface,
int new_width,
int new_height,
int timeout);
cairo_public void
cairo_os2_surface_refresh_window (cairo_surface_t *surface,
HPS hps_begin_paint,
PRECTL prcl_begin_paint_rect);
cairo_public void
cairo_os2_surface_set_manual_window_refresh (cairo_surface_t *surface,
cairo_bool_t manual_refresh);
cairo_public cairo_bool_t
cairo_os2_surface_get_manual_window_refresh (cairo_surface_t *surface);
#else /* CAIRO_HAS_OS2_SURFACE */
# error Cairo was not compiled with support for the OS/2 backend
#endif /* CAIRO_HAS_OS2_SURFACE */
CAIRO_END_DECLS
#endif /* _CAIRO_OS2_H_ */

View file

@ -0,0 +1,176 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
#ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H
#define CAIRO_OUTPUT_STREAM_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
const unsigned char *data,
unsigned int length);
typedef cairo_status_t (*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
struct _cairo_output_stream {
cairo_output_stream_write_func_t write_func;
cairo_output_stream_close_func_t close_func;
unsigned long position;
cairo_status_t status;
cairo_bool_t closed;
};
extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil;
cairo_private void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_close_func_t close_func);
cairo_private cairo_status_t
_cairo_output_stream_fini (cairo_output_stream_t *stream);
/* We already have the following declared in cairo.h:
typedef cairo_status_t (*cairo_write_func_t) (void *closure,
const unsigned char *data,
unsigned int length);
*/
typedef cairo_status_t (*cairo_close_func_t) (void *closure);
/* This function never returns %NULL. If an error occurs (NO_MEMORY)
* while trying to create the output stream this function returns a
* valid pointer to a nil output stream.
*
* Note that even with a nil surface, the close_func callback will be
* called by a call to _cairo_output_stream_close or
* _cairo_output_stream_destroy.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create (cairo_write_func_t write_func,
cairo_close_func_t close_func,
void *closure);
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status);
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */
cairo_private cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream);
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */
cairo_private cairo_status_t
_cairo_output_stream_destroy (cairo_output_stream_t *stream);
cairo_private void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length);
cairo_private void
_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
const unsigned char *data,
size_t length);
cairo_private void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt,
va_list ap) CAIRO_PRINTF_FORMAT ( 2, 0);
cairo_private void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt,
...) CAIRO_PRINTF_FORMAT (2, 3);
cairo_private long
_cairo_output_stream_get_position (cairo_output_stream_t *stream);
cairo_private cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream);
/* This function never returns %NULL. If an error occurs (NO_MEMORY or
* WRITE_ERROR) while trying to create the output stream this function
* returns a valid pointer to a nil output stream.
*
* Note: Even if a nil surface is returned, the caller should still
* call _cairo_output_stream_destroy (or _cairo_output_stream_close at
* least) in order to ensure that everything is properly cleaned up.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_for_filename (const char *filename);
/* This function never returns %NULL. If an error occurs (NO_MEMORY or
* WRITE_ERROR) while trying to create the output stream this function
* returns a valid pointer to a nil output stream.
*
* The caller still "owns" file and is responsible for calling fclose
* on it when finished. The stream will not do this itself.
*/
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_for_file (FILE *file);
cairo_private cairo_output_stream_t *
_cairo_memory_stream_create (void);
cairo_private void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest);
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
cairo_private cairo_output_stream_t *
_cairo_null_stream_create (void);
/* cairo-base85-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);
#endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */

View file

@ -0,0 +1,707 @@
/* cairo-output-stream.c: Output stream abstraction
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Author(s):
* Kristian Høgsberg <krh@redhat.com>
*/
#define _BSD_SOURCE /* for snprintf() */
#include "cairoint.h"
#include "cairo-output-stream-private.h"
#include "cairo-compiler-private.h"
#include <stdio.h>
#include <locale.h>
#include <ctype.h>
#include <errno.h>
/* Numbers printed with %f are printed with this number of significant
* digits after the decimal.
*/
#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
* bits of precision available after the decimal point.
*
* FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
* digits after the decimal point required to preserve the available
* precision.
*
* The conversion is:
*
* <programlisting>
* FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
* </programlisting>
*
* We can replace ceil(x) with (int)(x+1) since x will never be an
* integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
*/
#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))
void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
cairo_output_stream_close_func_t close_func)
{
stream->write_func = write_func;
stream->close_func = close_func;
stream->position = 0;
stream->status = CAIRO_STATUS_SUCCESS;
stream->closed = FALSE;
}
cairo_status_t
_cairo_output_stream_fini (cairo_output_stream_t *stream)
{
return _cairo_output_stream_close (stream);
}
const cairo_output_stream_t _cairo_output_stream_nil = {
NULL, /* write_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_NO_MEMORY,
FALSE /* closed */
};
static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
NULL, /* write_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_WRITE_ERROR,
FALSE /* closed */
};
typedef struct _cairo_output_stream_with_closure {
cairo_output_stream_t base;
cairo_write_func_t write_func;
cairo_close_func_t close_func;
void *closure;
} cairo_output_stream_with_closure_t;
static cairo_status_t
closure_write (cairo_output_stream_t *stream,
const unsigned char *data, unsigned int length)
{
cairo_output_stream_with_closure_t *stream_with_closure =
(cairo_output_stream_with_closure_t *) stream;
if (stream_with_closure->write_func == NULL)
return CAIRO_STATUS_SUCCESS;
return stream_with_closure->write_func (stream_with_closure->closure,
data, length);
}
static cairo_status_t
closure_close (cairo_output_stream_t *stream)
{
cairo_output_stream_with_closure_t *stream_with_closure =
(cairo_output_stream_with_closure_t *) stream;
if (stream_with_closure->close_func != NULL)
return stream_with_closure->close_func (stream_with_closure->closure);
else
return CAIRO_STATUS_SUCCESS;
}
cairo_output_stream_t *
_cairo_output_stream_create (cairo_write_func_t write_func,
cairo_close_func_t close_func,
void *closure)
{
cairo_output_stream_with_closure_t *stream;
stream = malloc (sizeof (cairo_output_stream_with_closure_t));
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, closure_write, closure_close);
stream->write_func = write_func;
stream->close_func = close_func;
stream->closure = closure;
return &stream->base;
}
cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status)
{
cairo_output_stream_t *stream;
/* check for the common ones */
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
if (status == CAIRO_STATUS_WRITE_ERROR)
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
stream = malloc (sizeof (cairo_output_stream_t));
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (stream, NULL, NULL);
stream->status = status;
return stream;
}
cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream)
{
cairo_status_t status;
if (stream->closed)
return stream->status;
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
if (stream->close_func) {
status = stream->close_func (stream);
/* Don't overwrite a pre-existing status failure. */
if (stream->status == CAIRO_STATUS_SUCCESS)
stream->status = status;
}
stream->closed = TRUE;
return stream->status;
}
cairo_status_t
_cairo_output_stream_destroy (cairo_output_stream_t *stream)
{
cairo_status_t status;
assert (stream != NULL);
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
status = _cairo_output_stream_fini (stream);
free (stream);
return status;
}
void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length)
{
if (length == 0)
return;
if (stream->status)
return;
stream->status = stream->write_func (stream, data, length);
stream->position += length;
}
void
_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
const unsigned char *data,
size_t length)
{
const char hex_chars[] = "0123456789abcdef";
char buffer[2];
unsigned int i, column;
if (stream->status)
return;
for (i = 0, column = 0; i < length; i++, column++) {
if (column == 38) {
_cairo_output_stream_write (stream, "\n", 1);
column = 0;
}
buffer[0] = hex_chars[(data[i] >> 4) & 0x0f];
buffer[1] = hex_chars[data[i] & 0x0f];
_cairo_output_stream_write (stream, buffer, 2);
}
}
/* Format a double in a locale independent way and trim trailing
* zeros. Based on code from Alex Larson <alexl@redhat.com>.
* http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
*
* The code in the patch is copyright Red Hat, Inc under the LGPL, but
* has been relicensed under the LGPL/MPL dual license for inclusion
* into cairo (see COPYING). -- Kristian Høgsberg <krh@redhat.com>
*/
static void
_cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision)
{
struct lconv *locale_data;
const char *decimal_point;
int decimal_point_len;
char *p;
int decimal_len;
int num_zeros, decimal_digits;
/* Omit the minus sign from negative zero. */
if (d == 0.0)
d = 0.0;
locale_data = localeconv ();
decimal_point = locale_data->decimal_point;
decimal_point_len = strlen (decimal_point);
assert (decimal_point_len != 0);
if (limited_precision) {
snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d);
} else {
/* Using "%f" to print numbers less than 0.1 will result in
* reduced precision due to the default 6 digits after the
* decimal point.
*
* For numbers is < 0.1, we print with maximum precision and count
* the number of zeros between the decimal point and the first
* significant digit. We then print the number again with the
* number of decimal places that gives us the required number of
* significant digits. This ensures the number is correctly
* rounded.
*/
if (fabs (d) >= 0.1) {
snprintf (buffer, size, "%f", d);
} else {
snprintf (buffer, size, "%.18f", d);
p = buffer;
if (*p == '+' || *p == '-')
p++;
while (isdigit (*p))
p++;
if (strncmp (p, decimal_point, decimal_point_len) == 0)
p += decimal_point_len;
num_zeros = 0;
while (*p++ == '0')
num_zeros++;
decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
if (decimal_digits < 18)
snprintf (buffer, size, "%.*f", decimal_digits, d);
}
}
p = buffer;
if (*p == '+' || *p == '-')
p++;
while (isdigit (*p))
p++;
if (strncmp (p, decimal_point, decimal_point_len) == 0) {
*p = '.';
decimal_len = strlen (p + decimal_point_len);
memmove (p + 1, p + decimal_point_len, decimal_len);
p[1 + decimal_len] = 0;
/* Remove trailing zeros and decimal point if possible. */
for (p = p + decimal_len; *p == '0'; p--)
*p = 0;
if (*p == '.') {
*p = 0;
p--;
}
}
}
enum {
LENGTH_MODIFIER_LONG = 0x100
};
/* Here's a limited reimplementation of printf. The reason for doing
* this is primarily to special case handling of doubles. We want
* locale independent formatting of doubles and we want to trim
* trailing zeros. This is handled by dtostr() above, and the code
* below handles everything else by calling snprintf() to do the
* formatting. This functionality is only for internal use and we
* only implement the formats we actually use.
*/
void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt, va_list ap)
{
#define SINGLE_FMT_BUFFER_SIZE 32
char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE];
int single_fmt_length;
char *p;
const char *f, *start;
int length_modifier, width;
cairo_bool_t var_width;
if (stream->status)
return;
f = fmt;
p = buffer;
while (*f != '\0') {
if (p == buffer + sizeof (buffer)) {
_cairo_output_stream_write (stream, buffer, sizeof (buffer));
p = buffer;
}
if (*f != '%') {
*p++ = *f++;
continue;
}
start = f;
f++;
if (*f == '0')
f++;
var_width = FALSE;
if (*f == '*') {
var_width = TRUE;
f++;
}
while (isdigit (*f))
f++;
length_modifier = 0;
if (*f == 'l') {
length_modifier = LENGTH_MODIFIER_LONG;
f++;
}
/* The only format strings exist in the cairo implementation
* itself. So there's an internal consistency problem if any
* of them is larger than our format buffer size. */
single_fmt_length = f - start + 1;
assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE);
/* Reuse the format string for this conversion. */
memcpy (single_fmt, start, single_fmt_length);
single_fmt[single_fmt_length] = '\0';
/* Flush contents of buffer before snprintf()'ing into it. */
_cairo_output_stream_write (stream, buffer, p - buffer);
/* We group signed and unsigned together in this switch, the
* only thing that matters here is the size of the arguments,
* since we're just passing the data through to sprintf(). */
switch (*f | length_modifier) {
case '%':
buffer[0] = *f;
buffer[1] = 0;
break;
case 'd':
case 'u':
case 'o':
case 'x':
case 'X':
if (var_width) {
width = va_arg (ap, int);
snprintf (buffer, sizeof buffer,
single_fmt, width, va_arg (ap, int));
} else {
snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
}
break;
case 'd' | LENGTH_MODIFIER_LONG:
case 'u' | LENGTH_MODIFIER_LONG:
case 'o' | LENGTH_MODIFIER_LONG:
case 'x' | LENGTH_MODIFIER_LONG:
case 'X' | LENGTH_MODIFIER_LONG:
if (var_width) {
width = va_arg (ap, int);
snprintf (buffer, sizeof buffer,
single_fmt, width, va_arg (ap, long int));
} else {
snprintf (buffer, sizeof buffer,
single_fmt, va_arg (ap, long int));
}
break;
case 's':
snprintf (buffer, sizeof buffer,
single_fmt, va_arg (ap, const char *));
break;
case 'f':
_cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE);
break;
case 'g':
_cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE);
break;
case 'c':
buffer[0] = va_arg (ap, int);
buffer[1] = 0;
break;
default:
ASSERT_NOT_REACHED;
}
p = buffer + strlen (buffer);
f++;
}
_cairo_output_stream_write (stream, buffer, p - buffer);
}
void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
_cairo_output_stream_vprintf (stream, fmt, ap);
va_end (ap);
}
long
_cairo_output_stream_get_position (cairo_output_stream_t *stream)
{
return stream->position;
}
cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream)
{
return stream->status;
}
/* Maybe this should be a configure time option, so embedded targets
* don't have to pull in stdio. */
typedef struct _stdio_stream {
cairo_output_stream_t base;
FILE *file;
} stdio_stream_t;
static cairo_status_t
stdio_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
stdio_stream_t *stream = (stdio_stream_t *) base;
if (fwrite (data, 1, length, stream->file) != length)
return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
stdio_flush (cairo_output_stream_t *base)
{
stdio_stream_t *stream = (stdio_stream_t *) base;
fflush (stream->file);
if (ferror (stream->file))
return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
else
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
stdio_close (cairo_output_stream_t *base)
{
cairo_status_t status;
stdio_stream_t *stream = (stdio_stream_t *) base;
status = stdio_flush (base);
fclose (stream->file);
return status;
}
cairo_output_stream_t *
_cairo_output_stream_create_for_file (FILE *file)
{
stdio_stream_t *stream;
if (file == NULL) {
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
stream = malloc (sizeof *stream);
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
stream->file = file;
return &stream->base;
}
cairo_output_stream_t *
_cairo_output_stream_create_for_filename (const char *filename)
{
stdio_stream_t *stream;
FILE *file;
if (filename == NULL)
return _cairo_null_stream_create ();
file = fopen (filename, "wb");
if (file == NULL) {
switch (errno) {
case ENOMEM:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
default:
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
}
stream = malloc (sizeof *stream);
if (stream == NULL) {
fclose (file);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, stdio_write, stdio_close);
stream->file = file;
return &stream->base;
}
typedef struct _memory_stream {
cairo_output_stream_t base;
cairo_array_t array;
} memory_stream_t;
static cairo_status_t
memory_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
memory_stream_t *stream = (memory_stream_t *) base;
return _cairo_array_append_multiple (&stream->array, data, length);
}
static cairo_status_t
memory_close (cairo_output_stream_t *base)
{
memory_stream_t *stream = (memory_stream_t *) base;
_cairo_array_fini (&stream->array);
return CAIRO_STATUS_SUCCESS;
}
cairo_output_stream_t *
_cairo_memory_stream_create (void)
{
memory_stream_t *stream;
stream = malloc (sizeof *stream);
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, memory_write, memory_close);
_cairo_array_init (&stream->array, 1);
return &stream->base;
}
void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest)
{
memory_stream_t *stream = (memory_stream_t *) base;
if (dest->status)
return;
if (base->status) {
dest->status = base->status;
return;
}
_cairo_output_stream_write (dest,
_cairo_array_index (&stream->array, 0),
_cairo_array_num_elements (&stream->array));
}
int
_cairo_memory_stream_length (cairo_output_stream_t *base)
{
memory_stream_t *stream = (memory_stream_t *) base;
return _cairo_array_num_elements (&stream->array);
}
static cairo_status_t
null_write (cairo_output_stream_t *base,
const unsigned char *data, unsigned int length)
{
return CAIRO_STATUS_SUCCESS;
}
cairo_output_stream_t *
_cairo_null_stream_create (void)
{
cairo_output_stream_t *stream;
stream = malloc (sizeof *stream);
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (stream, null_write, NULL);
return stream;
}

View file

@ -0,0 +1,167 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
#ifndef CAIRO_PAGINATED_H
#define CAIRO_PAGINATED_H
#include "cairoint.h"
struct _cairo_paginated_surface_backend {
/* Optional. Will be called once for each page.
*
* Note: With respect to the order of drawing operations as seen
* by the target, this call will occur before any drawing
* operations for the relevant page. However, with respect to the
* function calls as made by the user, this call will be *after*
* any drawing operations for the page, (that is, it will occur
* during the user's call to cairo_show_page or cairo_copy_page).
*/
cairo_warn cairo_int_status_t
(*start_page) (void *surface);
/* Required. Will be called twice for each page, once with an
* argument of CAIRO_PAGINATED_MODE_ANALYZE and once with
* CAIRO_PAGINATED_MODE_RENDER. See more details in the
* documentation for _cairo_paginated_surface_create below.
*/
void
(*set_paginated_mode) (void *surface,
cairo_paginated_mode_t mode);
/* Optional. Specifies the smallest box that encloses all objects
* on the page. Will be called at the end of the ANALYZE phase but
* before the mode is changed to RENDER.
*/
cairo_warn cairo_int_status_t
(*set_bounding_box) (void *surface,
cairo_box_t *bbox);
/* Optional. Indicates whether the page requires fallback images.
* Will be called at the end of the ANALYZE phase but before the
* mode is changed to RENDER.
*/
cairo_warn cairo_int_status_t
(*set_fallback_images_required) (void *surface,
cairo_bool_t fallbacks_required);
cairo_bool_t
(*supports_fine_grained_fallbacks) (void *surface);
};
/* A #cairo_paginated_surface_t provides a very convenient wrapper that
* is well-suited for doing the analysis common to most surfaces that
* have paginated output, (that is, things directed at printers, or
* for saving content in files such as PostScript or PDF files).
*
* To use the paginated surface, you'll first need to create your
* 'real' surface using _cairo_surface_init() and the standard
* #cairo_surface_backend_t. Then you also call
* _cairo_paginated_surface_create which takes its own, much simpler,
* #cairo_paginated_surface_backend_t. You are free to return the result
* of _cairo_paginated_surface_create() from your public
* cairo_<foo>_surface_create(). The paginated backend will be careful
* to not let the user see that they really got a "wrapped"
* surface. See test-paginated-surface.c for a fairly minimal example
* of a paginated-using surface. That should be a reasonable example
* to follow.
*
* What the paginated surface does is first save all drawing
* operations for a page into a meta-surface. Then when the user calls
* cairo_show_page(), the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create()):
*
* 1. Calls start_page() (if not %NULL). At this point, it is appropriate
* for the target to emit any page-specific header information into
* its output.
*
* 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the meta-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
*
* 4. Calls set_bounding_box() to provide the target surface with the
* tight bounding box of the page.
*
* 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
*
* 6. Replays a subset of the meta-surface operations to the target surface
*
* 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
*
* 8. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image
* surface to the target.
*
* So, the target will see drawing operations during three separate
* stages, (ANALYZE, RENDER and FALLBACK). During the ANALYZE phase
* the target should not actually perform any rendering, (for example,
* if performing output to a file, no output should be generated
* during this stage). Instead the drawing functions simply need to
* return %CAIRO_STATUS_SUCCESS or %CAIRO_INT_STATUS_UNSUPPORTED to
* indicate whether rendering would be supported. And it should do
* this as quickly as possible. The FALLBACK phase allows the surface
* to distinguish fallback images from native rendering in case they
* need to be handled as a special case.
*
* Note: The paginated surface layer assumes that the target surface
* is "blank" by default at the beginning of each page, without any
* need for an explicit erase operation, (as opposed to an image
* surface, for example, which might have uninitialized content
* originally). As such, it optimizes away CLEAR operations that
* happen at the beginning of each page---the target surface will not
* even see these operations.
*/
cairo_private cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend);
cairo_private cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface);
cairo_private cairo_bool_t
_cairo_surface_is_paginated (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height);
#endif /* CAIRO_PAGINATED_H */

View file

@ -0,0 +1,72 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
*/
#ifndef CAIRO_PAGINATED_SURFACE_H
#define CAIRO_PAGINATED_SURFACE_H
#include "cairo.h"
#include "cairo-surface-private.h"
typedef struct _cairo_paginated_surface {
cairo_surface_t base;
/* The target surface to hold the final result. */
cairo_surface_t *target;
cairo_content_t content;
/* XXX: These shouldn't actually exist. We inherit this ugliness
* from _cairo_meta_surface_create. The width/height parameters
* from that function also should not exist. The fix that will
* allow us to remove all of these is to fix acquire_source_image
* to pass an interest rectangle. */
int width;
int height;
/* Paginated-surface specific functions for the target */
const cairo_paginated_surface_backend_t *backend;
/* A cairo_meta_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
cairo_surface_t *meta;
int page_num;
cairo_bool_t page_is_blank;
} cairo_paginated_surface_t;
#endif /* CAIRO_PAGINATED_SURFACE_H */

View file

@ -0,0 +1,693 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
* Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/
/* The paginated surface layer exists to provide as much code sharing
* as possible for the various paginated surface backends in cairo
* (PostScript, PDF, etc.). See cairo-paginated-private.h for
* more details on how it works and how to use it.
*/
#include "cairoint.h"
#include "cairo-paginated-private.h"
#include "cairo-paginated-surface-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-analysis-surface-private.h"
static const cairo_surface_backend_t cairo_paginated_surface_backend;
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface);
static cairo_surface_t *
_cairo_paginated_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
return cairo_surface_create_similar (surface->target, content,
width, height);
}
/* XXX The integer width,height here should be doubles and all uses updated */
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
int width,
int height,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
cairo_status_t status;
surface = malloc (sizeof (cairo_paginated_surface_t));
if (surface == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
_cairo_surface_init (&surface->base, &cairo_paginated_surface_backend,
content);
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
surface->base.type = cairo_surface_get_type (target);
surface->target = cairo_surface_reference (target);
surface->content = content;
surface->width = width;
surface->height = height;
surface->backend = backend;
surface->meta = _cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
if (status)
goto FAIL_CLEANUP_SURFACE;
surface->page_num = 1;
surface->page_is_blank = TRUE;
return &surface->base;
FAIL_CLEANUP_SURFACE:
cairo_surface_destroy (target);
free (surface);
FAIL:
return _cairo_surface_create_in_error (status);
}
cairo_bool_t
_cairo_surface_is_paginated (cairo_surface_t *surface)
{
return surface->backend == &cairo_paginated_surface_backend;
}
cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface)
{
cairo_paginated_surface_t *paginated_surface;
assert (_cairo_surface_is_paginated (surface));
paginated_surface = (cairo_paginated_surface_t *) surface;
return paginated_surface->target;
}
cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width,
int height)
{
cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
assert (_cairo_surface_is_paginated (surface));
paginated_surface = (cairo_paginated_surface_t *) surface;
paginated_surface->width = width;
paginated_surface->height = height;
cairo_surface_destroy (paginated_surface->meta);
paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content,
width, height);
status = cairo_surface_status (paginated_surface->meta);
if (status)
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->page_is_blank == FALSE || surface->page_num == 1) {
cairo_surface_show_page (abstract_surface);
status = cairo_surface_status (abstract_surface);
}
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_finish (surface->target);
status = cairo_surface_status (surface->target);
}
if (status == CAIRO_STATUS_SUCCESS) {
cairo_surface_finish (surface->meta);
status = cairo_surface_status (surface->meta);
}
cairo_surface_destroy (surface->target);
cairo_surface_destroy (surface->meta);
return status;
}
static cairo_surface_t *
_cairo_paginated_surface_create_image_surface (void *abstract_surface,
int width,
int height)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_surface_t *image;
cairo_font_options_t options;
image = _cairo_image_surface_create_with_content (surface->content,
width,
height);
cairo_surface_get_font_options (&surface->base, &options);
_cairo_surface_set_font_options (image, &options);
return image;
}
static cairo_status_t
_cairo_paginated_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_surface_t *image;
cairo_status_t status;
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface->target, &extents);
if (status)
return status;
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
extents.height);
status = _cairo_meta_surface_replay (surface->meta, image);
if (status) {
cairo_surface_destroy (image);
return status;
}
*image_out = (cairo_image_surface_t*) image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_paginated_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
void *image_extra)
{
cairo_surface_destroy (&image->base);
}
static cairo_int_status_t
_paint_fallback_image (cairo_paginated_surface_t *surface,
cairo_box_int_t *box)
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
cairo_matrix_t matrix;
int x, y, width, height;
cairo_status_t status;
cairo_surface_t *image;
cairo_pattern_t *pattern;
x = box->p1.x;
y = box->p1.y;
width = box->p2.x - x;
height = box->p2.y - y;
image = _cairo_paginated_surface_create_image_surface (surface,
ceil (width * x_scale),
ceil (height * y_scale));
_cairo_surface_set_device_scale (image, x_scale, y_scale);
/* set_device_offset just sets the x0/y0 components of the matrix;
* so we have to do the scaling manually. */
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
status = _cairo_meta_surface_replay (surface->meta, image);
if (status)
goto CLEANUP_IMAGE;
pattern = cairo_pattern_create_for_surface (image);
cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
cairo_pattern_set_matrix (pattern, &matrix);
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
pattern);
cairo_pattern_destroy (pattern);
CLEANUP_IMAGE:
cairo_surface_destroy (image);
return status;
}
static cairo_int_status_t
_paint_page (cairo_paginated_surface_t *surface)
{
cairo_surface_t *analysis;
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
if (surface->target->status)
return surface->target->status;
analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height);
if (analysis->status)
return _cairo_surface_set_error (surface->target, analysis->status);
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_meta_surface_replay_and_create_regions (surface->meta,
analysis);
if (status || analysis->status) {
if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status;
goto FAIL;
}
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
if (status)
goto FAIL;
}
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
status = surface->backend->set_fallback_images_required (surface->target,
has_fallbacks);
if (status)
goto FAIL;
}
/* Finer grained fallbacks are currently only supported for some
* surface types */
if (surface->backend->supports_fine_grained_fallbacks != NULL &&
surface->backend->supports_fine_grained_fallbacks (surface->target))
{
has_supported = _cairo_analysis_surface_has_supported (analysis);
has_page_fallback = FALSE;
has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
}
else
{
if (_cairo_analysis_surface_has_unsupported (analysis)) {
has_supported = FALSE;
has_page_fallback = TRUE;
} else {
has_supported = TRUE;
has_page_fallback = FALSE;
}
has_finegrained_fallback = FALSE;
}
if (has_supported) {
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_RENDER);
status = _cairo_meta_surface_replay_region (surface->meta,
surface->target,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (status)
goto FAIL;
}
if (has_page_fallback) {
cairo_box_int_t box;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
box.p1.x = 0;
box.p1.y = 0;
box.p2.x = surface->width;
box.p2.y = surface->height;
status = _paint_fallback_image (surface, &box);
if (status)
goto FAIL;
}
if (has_finegrained_fallback) {
cairo_region_t *region;
cairo_box_int_t *boxes;
int num_boxes, i;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
/* Reset clip region before drawing the fall back images */
status = _cairo_surface_intersect_clip_path (surface->target,
NULL,
CAIRO_FILL_RULE_WINDING,
CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_DEFAULT);
if (status)
goto FAIL;
region = _cairo_analysis_surface_get_unsupported (analysis);
status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
if (status)
goto FAIL;
for (i = 0; i < num_boxes; i++) {
status = _paint_fallback_image (surface, &boxes[i]);
if (status) {
_cairo_region_boxes_fini (region, boxes);
goto FAIL;
}
}
_cairo_region_boxes_fini (region, boxes);
}
FAIL:
cairo_surface_destroy (analysis);
return _cairo_surface_set_error (surface->target, status);
}
static cairo_status_t
_start_page (cairo_paginated_surface_t *surface)
{
if (surface->target->status)
return surface->target->status;
if (! surface->backend->start_page)
return CAIRO_STATUS_SUCCESS;
return _cairo_surface_set_error (surface->target,
surface->backend->start_page (surface->target));
}
static cairo_int_status_t
_cairo_paginated_surface_copy_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
if (status)
return status;
status = _paint_page (surface);
if (status)
return status;
surface->page_num++;
/* XXX: It might make sense to add some suport here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
* show_page and we implement the copying by simply not destroying
* the meta-surface. */
cairo_surface_show_page (surface->target);
return cairo_surface_status (surface->target);
}
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface)
{
cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
if (status)
return status;
status = _paint_page (surface);
if (status)
return status;
cairo_surface_show_page (surface->target);
status = cairo_surface_status (surface->target);
if (status)
return status;
status = cairo_surface_status (surface->meta);
if (status)
return status;
cairo_surface_destroy (surface->meta);
surface->meta = _cairo_meta_surface_create (surface->content,
surface->width,
surface->height);
status = cairo_surface_status (surface->meta);
if (status)
return status;
surface->page_num++;
surface->page_is_blank = TRUE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_paginated_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_intersect_clip_path (surface->meta,
path, fill_rule,
tolerance, antialias);
}
static cairo_int_status_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_get_extents (surface->target, rectangle);
}
static void
_cairo_paginated_surface_get_font_options (void *abstract_surface,
cairo_font_options_t *options)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_surface_get_font_options (surface->target, options);
}
static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source)
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_paint (surface->meta, op, source);
}
static cairo_int_status_t
_cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_mask (surface->meta, op, source, mask);
}
static cairo_int_status_t
_cairo_paginated_surface_stroke (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias)
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
tolerance, antialias);
}
static cairo_int_status_t
_cairo_paginated_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias)
{
cairo_paginated_surface_t *surface = abstract_surface;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
tolerance, antialias);
}
static cairo_bool_t
_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
return cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS;
surface->page_is_blank = FALSE;
/* Since this is a "wrapping" surface, we're calling back into
* _cairo_surface_show_text_glyphs from within a call to the same.
* Since _cairo_surface_show_text_glyphs acquires a mutex, we release
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
* adding locking code to all 18 surface-backend-specific
* show_glyphs functions, (which would get less testing and likely
* lead to bugs).
*/
status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
scaled_font);
return status;
}
static cairo_surface_t *
_cairo_paginated_surface_snapshot (void *abstract_other)
{
cairo_paginated_surface_t *other = abstract_other;
return _cairo_surface_snapshot (other->meta);
}
static const cairo_surface_backend_t cairo_paginated_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
_cairo_paginated_surface_create_similar,
_cairo_paginated_surface_finish,
_cairo_paginated_surface_acquire_source_image,
_cairo_paginated_surface_release_source_image,
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
NULL, /* set_clip_region */
_cairo_paginated_surface_intersect_clip_path,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
_cairo_paginated_surface_paint,
_cairo_paginated_surface_mask,
_cairo_paginated_surface_stroke,
_cairo_paginated_surface_fill,
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_paginated_surface_has_show_text_glyphs,
_cairo_paginated_surface_show_text_glyphs
};

View file

@ -0,0 +1,174 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
typedef struct cairo_path_bounder {
cairo_point_t move_to_point;
cairo_bool_t has_move_to_point;
cairo_bool_t has_point;
cairo_fixed_t min_x;
cairo_fixed_t min_y;
cairo_fixed_t max_x;
cairo_fixed_t max_y;
} cairo_path_bounder_t;
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder);
static void
_cairo_path_bounder_fini (cairo_path_bounder_t *bounder);
static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point);
static cairo_status_t
_cairo_path_bounder_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
_cairo_path_bounder_close_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
{
bounder->has_move_to_point = FALSE;
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_fini (cairo_path_bounder_t *bounder)
{
bounder->has_move_to_point = FALSE;
bounder->has_point = FALSE;
}
static void
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point)
{
if (bounder->has_point) {
if (point->x < bounder->min_x)
bounder->min_x = point->x;
if (point->y < bounder->min_y)
bounder->min_y = point->y;
if (point->x > bounder->max_x)
bounder->max_x = point->x;
if (point->y > bounder->max_y)
bounder->max_y = point->y;
} else {
bounder->min_x = point->x;
bounder->min_y = point->y;
bounder->max_x = point->x;
bounder->max_y = point->y;
bounder->has_point = TRUE;
}
}
static cairo_status_t
_cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
bounder->move_to_point = *point;
bounder->has_move_to_point = TRUE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
if (bounder->has_move_to_point) {
_cairo_path_bounder_add_point (bounder,
&bounder->move_to_point);
bounder->has_move_to_point = FALSE;
}
_cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
cairo_status_t
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2,
double tolerance)
{
cairo_path_bounder_t bounder;
cairo_status_t status;
_cairo_path_bounder_init (&bounder);
status = _cairo_path_fixed_interpret_flat (path, CAIRO_DIRECTION_FORWARD,
_cairo_path_bounder_move_to,
_cairo_path_bounder_line_to,
_cairo_path_bounder_close_path,
&bounder,
tolerance);
if (status == CAIRO_STATUS_SUCCESS && bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.min_x);
*y1 = _cairo_fixed_to_double (bounder.min_y);
*x2 = _cairo_fixed_to_double (bounder.max_x);
*y2 = _cairo_fixed_to_double (bounder.max_y);
} else {
*x1 = 0.0;
*y1 = 0.0;
*x2 = 0.0;
*y2 = 0.0;
}
_cairo_path_bounder_fini (&bounder);
return status;
}

View file

@ -0,0 +1,239 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
typedef struct cairo_filler {
double tolerance;
cairo_traps_t *traps;
cairo_point_t current_point;
cairo_polygon_t polygon;
} cairo_filler_t;
static void
_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps);
static void
_cairo_filler_fini (cairo_filler_t *filler);
static cairo_status_t
_cairo_filler_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
_cairo_filler_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
_cairo_filler_curve_to (void *closure,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d);
static cairo_status_t
_cairo_filler_close_path (void *closure);
static void
_cairo_filler_init (cairo_filler_t *filler, double tolerance, cairo_traps_t *traps)
{
filler->tolerance = tolerance;
filler->traps = traps;
filler->current_point.x = 0;
filler->current_point.y = 0;
_cairo_polygon_init (&filler->polygon);
}
static void
_cairo_filler_fini (cairo_filler_t *filler)
{
_cairo_polygon_fini (&filler->polygon);
}
static cairo_status_t
_cairo_filler_move_to (void *closure, cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
_cairo_polygon_move_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
}
static cairo_status_t
_cairo_filler_line_to (void *closure, cairo_point_t *point)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_line_to (polygon, point);
filler->current_point = *point;
return _cairo_polygon_status (&filler->polygon);
}
static cairo_status_t
_cairo_filler_curve_to (void *closure,
cairo_point_t *b,
cairo_point_t *c,
cairo_point_t *d)
{
int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
cairo_spline_t spline;
status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
if (status == CAIRO_INT_STATUS_DEGENERATE)
return CAIRO_STATUS_SUCCESS;
status = _cairo_spline_decompose (&spline, filler->tolerance);
if (status)
goto CLEANUP_SPLINE;
for (i = 1; i < spline.num_points; i++)
_cairo_polygon_line_to (polygon, &spline.points[i]);
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
filler->current_point = *d;
return status;
}
static cairo_status_t
_cairo_filler_close_path (void *closure)
{
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
_cairo_polygon_close (polygon);
return _cairo_polygon_status (polygon);
}
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps);
cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
status = _cairo_path_fixed_fill_rectangle (path, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_filler_init (&filler, tolerance, traps);
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
_cairo_filler_move_to,
_cairo_filler_line_to,
_cairo_filler_curve_to,
_cairo_filler_close_path,
&filler);
if (status)
goto BAIL;
_cairo_polygon_close (&filler.polygon);
status = _cairo_polygon_status (&filler.polygon);
if (status)
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps,
&filler.polygon,
fill_rule);
if (status)
goto BAIL;
BAIL:
_cairo_filler_fini (&filler);
return status;
}
/* This special-case filler supports only a path that describes a
* device-axis aligned rectangle. It exists to avoid the overhead of
* the general tessellator when drawing very common rectangles.
*
* If the path described anything but a device-axis aligned rectangle,
* this function will return %CAIRO_INT_STATUS_UNSUPPORTED.
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps)
{
if (_cairo_path_fixed_is_box (path, NULL)) {
cairo_point_t *p = path->buf_head.base.points;
cairo_point_t *top_left, *bot_right;
top_left = &p[0];
bot_right = &p[2];
if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
int n;
/* not a simple cairo_rectangle() */
for (n = 0; n < 4; n++) {
if (p[n].x <= top_left->x && p[n].y <= top_left->y)
top_left = &p[n];
if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
bot_right = &p[n];
}
}
return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
}

View file

@ -0,0 +1,80 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_PATH_FIXED_PRIVATE_H
#define CAIRO_PATH_FIXED_PRIVATE_H
#include "cairo-types-private.h"
enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
CAIRO_PATH_OP_LINE_TO = 1,
CAIRO_PATH_OP_CURVE_TO = 2,
CAIRO_PATH_OP_CLOSE_PATH = 3
};
/* we want to make sure a single byte is used for thie enum */
typedef char cairo_path_op_t;
/* make _cairo_path_fixed fit a 512 bytes. about 50 items */
#define CAIRO_PATH_BUF_SIZE ((512 - 4 * sizeof (void*) - sizeof (cairo_path_buf_t)) \
/ (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
typedef struct _cairo_path_buf {
struct _cairo_path_buf *next, *prev;
int buf_size;
int num_ops;
int num_points;
cairo_path_op_t *op;
cairo_point_t *points;
} cairo_path_buf_t;
typedef struct _cairo_path_buf_fixed {
cairo_path_buf_t base;
cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
cairo_point_t points[2 * CAIRO_PATH_BUF_SIZE];
} cairo_path_buf_fixed_t;
struct _cairo_path_fixed {
cairo_point_t last_move_point;
cairo_point_t current_point;
unsigned int has_current_point : 1;
unsigned int has_curve_to : 1;
cairo_path_buf_t *buf_tail;
cairo_path_buf_fixed_t buf_head;
};
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */

View file

@ -0,0 +1,896 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
#include "cairo-path-fixed-private.h"
/* private functions */
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
cairo_point_t *points,
int num_points);
static void
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf);
static cairo_path_buf_t *
_cairo_path_buf_create (int buf_size);
static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
static void
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op);
static void
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
cairo_point_t *points,
int num_points);
void
_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
path->buf_head.base.next = NULL;
path->buf_head.base.prev = NULL;
path->buf_tail = &path->buf_head.base;
path->buf_head.base.num_ops = 0;
path->buf_head.base.num_points = 0;
path->buf_head.base.buf_size = CAIRO_PATH_BUF_SIZE;
path->buf_head.base.op = path->buf_head.op;
path->buf_head.base.points = path->buf_head.points;
path->current_point.x = 0;
path->current_point.y = 0;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
path->last_move_point = path->current_point;
}
cairo_status_t
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
{
cairo_path_buf_t *buf, *other_buf;
unsigned int num_points, num_ops, buf_size;
_cairo_path_fixed_init (path);
path->current_point = other->current_point;
path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to;
path->last_move_point = other->last_move_point;
path->buf_head.base.num_ops = other->buf_head.base.num_ops;
path->buf_head.base.num_points = other->buf_head.base.num_points;
path->buf_head.base.buf_size = other->buf_head.base.buf_size;
memcpy (path->buf_head.op, other->buf_head.base.op,
other->buf_head.base.num_ops * sizeof (other->buf_head.op[0]));
memcpy (path->buf_head.points, other->buf_head.points,
other->buf_head.base.num_points * sizeof (other->buf_head.points[0]));
num_points = num_ops = 0;
for (other_buf = other->buf_head.base.next;
other_buf != NULL;
other_buf = other_buf->next)
{
num_ops += other_buf->num_ops;
num_points += other_buf->num_points;
}
buf_size = MAX (num_ops, (num_points + 1) / 2);
if (buf_size) {
buf = _cairo_path_buf_create (buf_size);
if (buf == NULL) {
_cairo_path_fixed_fini (path);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
for (other_buf = other->buf_head.base.next;
other_buf != NULL;
other_buf = other_buf->next)
{
memcpy (buf->op + buf->num_ops, other_buf->op,
other_buf->num_ops * sizeof (buf->op[0]));
buf->num_ops += other_buf->num_ops;
memcpy (buf->points + buf->num_points, other_buf->points,
other_buf->num_points * sizeof (buf->points[0]));
buf->num_points += other_buf->num_points;
}
_cairo_path_fixed_add_buf (path, buf);
}
return CAIRO_STATUS_SUCCESS;
}
cairo_path_fixed_t *
_cairo_path_fixed_create (void)
{
cairo_path_fixed_t *path;
path = malloc (sizeof (cairo_path_fixed_t));
if (!path) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
_cairo_path_fixed_init (path);
return path;
}
void
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
{
cairo_path_buf_t *buf;
buf = path->buf_head.base.next;
while (buf) {
cairo_path_buf_t *this = buf;
buf = buf->next;
_cairo_path_buf_destroy (this);
}
path->buf_head.base.next = NULL;
path->buf_head.base.prev = NULL;
path->buf_tail = &path->buf_head.base;
path->buf_head.base.num_ops = 0;
path->buf_head.base.num_points = 0;
path->has_current_point = FALSE;
path->has_curve_to = FALSE;
}
void
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
{
_cairo_path_fixed_fini (path);
free (path);
}
cairo_status_t
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
cairo_point_t point;
point.x = x;
point.y = y;
/* If the previous op was also a MOVE_TO, then just change its
* point rather than adding a new op. */
if (path->buf_tail && path->buf_tail->num_ops &&
path->buf_tail->op[path->buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO)
{
cairo_point_t *last_move_to_point;
last_move_to_point = &path->buf_tail->points[path->buf_tail->num_points - 1];
*last_move_to_point = point;
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
if (status)
return status;
}
path->current_point = point;
path->has_current_point = TRUE;
path->last_move_point = path->current_point;
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
{
path->has_current_point = FALSE;
}
cairo_status_t
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy)
{
cairo_fixed_t x, y;
if (! path->has_current_point)
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x = path->current_point.x + dx;
y = path->current_point.y + dy;
return _cairo_path_fixed_move_to (path, x, y);
}
cairo_status_t
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
cairo_fixed_t x,
cairo_fixed_t y)
{
cairo_status_t status;
cairo_point_t point;
point.x = x;
point.y = y;
/* When there is not yet a current point, the line_to operation
* becomes a move_to instead. Note: We have to do this by
* explicitly calling into _cairo_path_fixed_line_to to ensure
* that the last_move_point state is updated properly.
*/
if (! path->has_current_point)
status = _cairo_path_fixed_move_to (path, point.x, point.y);
else
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
if (status)
return status;
path->current_point = point;
path->has_current_point = TRUE;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
cairo_fixed_t dx,
cairo_fixed_t dy)
{
cairo_fixed_t x, y;
if (! path->has_current_point)
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x = path->current_point.x + dx;
y = path->current_point.y + dy;
return _cairo_path_fixed_line_to (path, x, y);
}
cairo_status_t
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t x0, cairo_fixed_t y0,
cairo_fixed_t x1, cairo_fixed_t y1,
cairo_fixed_t x2, cairo_fixed_t y2)
{
cairo_status_t status;
cairo_point_t point[3];
point[0].x = x0; point[0].y = y0;
point[1].x = x1; point[1].y = y1;
point[2].x = x2; point[2].y = y2;
if (! path->has_current_point) {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
&point[0], 1);
if (status)
return status;
}
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
if (status)
return status;
path->current_point = point[2];
path->has_current_point = TRUE;
path->has_curve_to = TRUE;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t dx0, cairo_fixed_t dy0,
cairo_fixed_t dx1, cairo_fixed_t dy1,
cairo_fixed_t dx2, cairo_fixed_t dy2)
{
cairo_fixed_t x0, y0;
cairo_fixed_t x1, y1;
cairo_fixed_t x2, y2;
if (! path->has_current_point)
return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x0 = path->current_point.x + dx0;
y0 = path->current_point.y + dy0;
x1 = path->current_point.x + dx1;
y1 = path->current_point.y + dy1;
x2 = path->current_point.x + dx2;
y2 = path->current_point.y + dy2;
return _cairo_path_fixed_curve_to (path,
x0, y0,
x1, y1,
x2, y2);
}
cairo_status_t
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
{
cairo_status_t status;
if (! path->has_current_point)
return CAIRO_STATUS_SUCCESS;
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
if (status)
return status;
status = _cairo_path_fixed_move_to (path,
path->last_move_point.x,
path->last_move_point.y);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
cairo_fixed_t *x,
cairo_fixed_t *y)
{
if (! path->has_current_point)
return FALSE;
*x = path->current_point.x;
*y = path->current_point.y;
return TRUE;
}
static cairo_status_t
_cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_path_op_t op,
cairo_point_t *points,
int num_points)
{
cairo_path_buf_t *buf = path->buf_tail;
if (buf->num_ops + 1 > buf->buf_size ||
buf->num_points + num_points > 2 * buf->buf_size)
{
buf = _cairo_path_buf_create (buf->buf_size * 2);
if (buf == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_path_fixed_add_buf (path, buf);
}
_cairo_path_buf_add_op (buf, op);
_cairo_path_buf_add_points (buf, points, num_points);
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf)
{
buf->next = NULL;
buf->prev = path->buf_tail;
path->buf_tail->next = buf;
path->buf_tail = buf;
}
static cairo_path_buf_t *
_cairo_path_buf_create (int buf_size)
{
cairo_path_buf_t *buf;
/* adjust buf_size to ensure that buf->points is naturally aligned */
buf_size += sizeof (double)
- ((buf_size + sizeof (cairo_path_buf_t)) & (sizeof (double)-1));
buf = _cairo_malloc_ab_plus_c (buf_size,
sizeof (cairo_path_op_t) +
2 * sizeof (cairo_point_t),
sizeof (cairo_path_buf_t));
if (buf) {
buf->next = NULL;
buf->prev = NULL;
buf->num_ops = 0;
buf->num_points = 0;
buf->buf_size = buf_size;
buf->op = (cairo_path_op_t *) (buf + 1);
buf->points = (cairo_point_t *) (buf->op + buf_size);
}
return buf;
}
static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
{
free (buf);
}
static void
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
cairo_path_op_t op)
{
buf->op[buf->num_ops++] = op;
}
static void
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
cairo_point_t *points,
int num_points)
{
int i;
for (i=0; i < num_points; i++) {
buf->points[buf->num_points++] = points[i];
}
}
static int const num_args[] =
{
1, /* cairo_path_move_to */
1, /* cairo_path_op_line_to */
3, /* cairo_path_op_curve_to */
0, /* cairo_path_op_close_path */
};
cairo_status_t
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_curve_to_func_t *curve_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure)
{
cairo_status_t status;
const cairo_path_buf_t *buf;
cairo_path_op_t op;
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1;
for (buf = forward ? &path->buf_head.base : path->buf_tail;
buf;
buf = forward ? buf->next : buf->prev)
{
cairo_point_t *points;
int start, stop, i;
if (forward) {
start = 0;
stop = buf->num_ops;
points = buf->points;
} else {
start = buf->num_ops - 1;
stop = -1;
points = buf->points + buf->num_points;
}
for (i=start; i != stop; i += step) {
op = buf->op[i];
if (! forward) {
points -= num_args[(int) op];
}
switch (op) {
case CAIRO_PATH_OP_MOVE_TO:
status = (*move_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_LINE_TO:
status = (*line_to) (closure, &points[0]);
break;
case CAIRO_PATH_OP_CURVE_TO:
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
break;
case CAIRO_PATH_OP_CLOSE_PATH:
default:
status = (*close_path) (closure);
break;
}
if (status)
return status;
if (forward) {
points += num_args[(int) op];
}
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_append_move_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_move_to (path, point->x, point->y);
}
static cairo_status_t
_append_line_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_line_to (path, point->x, point->y);
}
static cairo_status_t
_append_curve_to (void *closure,
cairo_point_t *p0,
cairo_point_t *p1,
cairo_point_t *p2)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_curve_to (path, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y);
}
static cairo_status_t
_append_close_path (void *closure)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_close_path (path);
}
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir)
{
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
path);
}
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
cairo_fixed_t offy,
cairo_fixed_t scalex,
cairo_fixed_t scaley)
{
cairo_path_buf_t *buf = &path->buf_head.base;
int i;
while (buf) {
for (i = 0; i < buf->num_points; i++) {
if (scalex != CAIRO_FIXED_ONE)
buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex);
buf->points[i].x += offx;
if (scaley != CAIRO_FIXED_ONE)
buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley);
buf->points[i].y += offy;
}
buf = buf->next;
}
}
/**
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
* @matrix: a #cairo_matrix_t
*
* Transform the fixed-point path according to the given matrix.
* There is a fast path for the case where @matrix has no rotation
* or shear.
**/
void
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
int i;
double dx, dy;
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0),
_cairo_fixed_from_double (matrix->xx),
_cairo_fixed_from_double (matrix->yy));
return;
}
buf = &path->buf_head.base;
while (buf) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
dy = _cairo_fixed_to_double (buf->points[i].y);
cairo_matrix_transform_point (matrix, &dx, &dy);
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
}
buf = buf->next;
}
}
cairo_bool_t
_cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
cairo_path_fixed_t *other)
{
cairo_path_buf_t *path_buf, *other_buf;
if (path->current_point.x != other->current_point.x ||
path->current_point.y != other->current_point.y ||
path->has_current_point != other->has_current_point ||
path->has_curve_to != other->has_curve_to ||
path->last_move_point.x != other->last_move_point.x ||
path->last_move_point.y != other->last_move_point.y)
return FALSE;
other_buf = &other->buf_head.base;
for (path_buf = &path->buf_head.base;
path_buf != NULL;
path_buf = path_buf->next)
{
if (other_buf == NULL ||
path_buf->num_ops != other_buf->num_ops ||
path_buf->num_points != other_buf->num_points ||
memcmp (path_buf->op, other_buf->op,
sizeof (cairo_path_op_t) * path_buf->num_ops) != 0 ||
memcmp (path_buf->points, other_buf->points,
sizeof (cairo_point_t) * path_buf->num_points) != 0)
{
return FALSE;
}
other_buf = other_buf->next;
}
return TRUE;
}
/* Closure for path flattening */
typedef struct cairo_path_flattener {
double tolerance;
cairo_point_t current_point;
cairo_path_fixed_move_to_func_t *move_to;
cairo_path_fixed_line_to_func_t *line_to;
cairo_path_fixed_close_path_func_t *close_path;
void *closure;
} cpf_t;
static cairo_status_t
_cpf_move_to (void *closure, cairo_point_t *point)
{
cpf_t *cpf = closure;
cpf->current_point = *point;
return cpf->move_to (cpf->closure, point);
}
static cairo_status_t
_cpf_line_to (void *closure, cairo_point_t *point)
{
cpf_t *cpf = closure;
cpf->current_point = *point;
return cpf->line_to (cpf->closure, point);
}
static cairo_status_t
_cpf_curve_to (void *closure,
cairo_point_t *p1,
cairo_point_t *p2,
cairo_point_t *p3)
{
cpf_t *cpf = closure;
cairo_status_t status;
cairo_spline_t spline;
int i;
cairo_point_t *p0 = &cpf->current_point;
status = _cairo_spline_init (&spline, p0, p1, p2, p3);
if (status == CAIRO_INT_STATUS_DEGENERATE)
return CAIRO_STATUS_SUCCESS;
status = _cairo_spline_decompose (&spline, cpf->tolerance);
if (status)
goto out;
for (i=1; i < spline.num_points; i++) {
status = cpf->line_to (cpf->closure, &spline.points[i]);
if (status)
goto out;
}
cpf->current_point = *p3;
status = CAIRO_STATUS_SUCCESS;
out:
_cairo_spline_fini (&spline);
return status;
}
static cairo_status_t
_cpf_close_path (void *closure)
{
cpf_t *cpf = closure;
return cpf->close_path (cpf->closure);
}
cairo_status_t
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
cairo_path_fixed_close_path_func_t *close_path,
void *closure,
double tolerance)
{
cpf_t flattener;
flattener.tolerance = tolerance;
flattener.move_to = move_to;
flattener.line_to = line_to;
flattener.close_path = close_path;
flattener.closure = closure;
return _cairo_path_fixed_interpret (path, dir,
_cpf_move_to,
_cpf_line_to,
_cpf_curve_to,
_cpf_close_path,
&flattener);
}
cairo_bool_t
_cairo_path_fixed_is_empty (cairo_path_fixed_t *path)
{
if (path->buf_head.base.num_ops == 0)
return TRUE;
return FALSE;
}
/**
* Check whether the given path contains a single rectangle.
*/
cairo_bool_t
_cairo_path_fixed_is_box (cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf = &path->buf_head.base;
/* We can't have more than one buf for this check */
if (buf->next != NULL)
return FALSE;
/* Do we have the right number of ops? */
if (buf->num_ops != 5 && buf->num_ops != 6)
return FALSE;
/* Check whether the ops are those that would be used for a rectangle */
if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO ||
buf->op[1] != CAIRO_PATH_OP_LINE_TO ||
buf->op[2] != CAIRO_PATH_OP_LINE_TO ||
buf->op[3] != CAIRO_PATH_OP_LINE_TO)
{
return FALSE;
}
/* Now, there are choices. The rectangle might end with a LINE_TO
* (to the original point), but this isn't required. If it
* doesn't, then it must end with a CLOSE_PATH. */
if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) {
if (buf->points[4].x != buf->points[0].x ||
buf->points[4].y != buf->points[0].y)
return FALSE;
} else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
return FALSE;
}
if (buf->num_ops == 6) {
/* A trailing CLOSE_PATH or MOVE_TO is ok */
if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO &&
buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH)
return FALSE;
}
/* Ok, we may have a box, if the points line up */
if (buf->points[0].y == buf->points[1].y &&
buf->points[1].x == buf->points[2].x &&
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
if (box) {
box->p1 = buf->points[0];
box->p2 = buf->points[2];
}
return TRUE;
}
if (buf->points[0].x == buf->points[1].x &&
buf->points[1].y == buf->points[2].y &&
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
if (box) {
box->p1 = buf->points[0];
box->p2 = buf->points[2];
}
return TRUE;
}
return FALSE;
}
/*
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
* <informalexample><programlisting>
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
cairo_box_t *box)
{
cairo_path_buf_t *buf = &path->buf_head.base;
if (!_cairo_path_fixed_is_box (path, box))
return FALSE;
if (buf->points[0].y == buf->points[1].y)
return TRUE;
return FALSE;
}

View file

@ -0,0 +1,57 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_PATH_PRIVATE_H
#define CAIRO_PATH_PRIVATE_H
#include "cairoint.h"
cairo_private cairo_path_t *
_cairo_path_create (cairo_path_fixed_t *path,
cairo_gstate_t *gstate);
cairo_private cairo_path_t *
_cairo_path_create_flat (cairo_path_fixed_t *path,
cairo_gstate_t *gstate);
cairo_private cairo_path_t *
_cairo_path_create_in_error (cairo_status_t status);
cairo_private cairo_status_t
_cairo_path_append_to_context (const cairo_path_t *path,
cairo_t *cr);
#endif /* CAIRO_PATH_DATA_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,482 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
* Copyright © 2006 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#include "cairoint.h"
#include "cairo-path-private.h"
#include "cairo-path-fixed-private.h"
static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
/* Closure for path interpretation. */
typedef struct cairo_path_count {
int count;
cairo_point_t current_point;
} cpc_t;
static cairo_status_t
_cpc_move_to (void *closure, cairo_point_t *point)
{
cpc_t *cpc = closure;
cpc->count += 2;
cpc->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpc_line_to (void *closure, cairo_point_t *point)
{
cpc_t *cpc = closure;
cpc->count += 2;
cpc->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpc_curve_to (void *closure,
cairo_point_t *p1,
cairo_point_t *p2,
cairo_point_t *p3)
{
cpc_t *cpc = closure;
cpc->count += 4;
cpc->current_point = *p3;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpc_close_path (void *closure)
{
cpc_t *cpc = closure;
cpc->count += 1;
return CAIRO_STATUS_SUCCESS;
}
static int
_cairo_path_count (cairo_path_t *path,
cairo_path_fixed_t *path_fixed,
double tolerance,
cairo_bool_t flatten)
{
cairo_status_t status;
cpc_t cpc;
cpc.count = 0;
cpc.current_point.x = 0;
cpc.current_point.y = 0;
if (flatten) {
status = _cairo_path_fixed_interpret_flat (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpc_move_to,
_cpc_line_to,
_cpc_close_path,
&cpc,
tolerance);
} else {
status = _cairo_path_fixed_interpret (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpc_move_to,
_cpc_line_to,
_cpc_curve_to,
_cpc_close_path,
&cpc);
}
if (status)
return -1;
return cpc.count;
}
/* Closure for path interpretation. */
typedef struct cairo_path_populate {
cairo_path_data_t *data;
cairo_gstate_t *gstate;
cairo_point_t current_point;
} cpp_t;
static cairo_status_t
_cpp_move_to (void *closure, cairo_point_t *point)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x, y;
x = _cairo_fixed_to_double (point->x);
y = _cairo_fixed_to_double (point->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
data->header.type = CAIRO_PATH_MOVE_TO;
data->header.length = 2;
/* We index from 1 to leave room for data->header */
data[1].point.x = x;
data[1].point.y = y;
cpp->data += data->header.length;
cpp->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpp_line_to (void *closure, cairo_point_t *point)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x, y;
x = _cairo_fixed_to_double (point->x);
y = _cairo_fixed_to_double (point->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
data->header.type = CAIRO_PATH_LINE_TO;
data->header.length = 2;
/* We index from 1 to leave room for data->header */
data[1].point.x = x;
data[1].point.y = y;
cpp->data += data->header.length;
cpp->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpp_curve_to (void *closure,
cairo_point_t *p1,
cairo_point_t *p2,
cairo_point_t *p3)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
double x1, y1;
double x2, y2;
double x3, y3;
x1 = _cairo_fixed_to_double (p1->x);
y1 = _cairo_fixed_to_double (p1->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x1, &y1);
x2 = _cairo_fixed_to_double (p2->x);
y2 = _cairo_fixed_to_double (p2->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
x3 = _cairo_fixed_to_double (p3->x);
y3 = _cairo_fixed_to_double (p3->y);
_cairo_gstate_backend_to_user (cpp->gstate, &x3, &y3);
data->header.type = CAIRO_PATH_CURVE_TO;
data->header.length = 4;
/* We index from 1 to leave room for data->header */
data[1].point.x = x1;
data[1].point.y = y1;
data[2].point.x = x2;
data[2].point.y = y2;
data[3].point.x = x3;
data[3].point.y = y3;
cpp->data += data->header.length;
cpp->current_point = *p3;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cpp_close_path (void *closure)
{
cpp_t *cpp = closure;
cairo_path_data_t *data = cpp->data;
data->header.type = CAIRO_PATH_CLOSE_PATH;
data->header.length = 1;
cpp->data += data->header.length;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_path_populate (cairo_path_t *path,
cairo_path_fixed_t *path_fixed,
cairo_gstate_t *gstate,
cairo_bool_t flatten)
{
cairo_status_t status;
cpp_t cpp;
cpp.data = path->data;
cpp.gstate = gstate;
cpp.current_point.x = 0;
cpp.current_point.y = 0;
if (flatten) {
double tolerance = _cairo_gstate_get_tolerance (gstate);
status = _cairo_path_fixed_interpret_flat (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpp_move_to,
_cpp_line_to,
_cpp_close_path,
&cpp,
tolerance);
} else {
status = _cairo_path_fixed_interpret (path_fixed,
CAIRO_DIRECTION_FORWARD,
_cpp_move_to,
_cpp_line_to,
_cpp_curve_to,
_cpp_close_path,
&cpp);
}
if (status)
return status;
/* Sanity check the count */
assert (cpp.data - path->data == path->num_data);
return CAIRO_STATUS_SUCCESS;
}
cairo_path_t *
_cairo_path_create_in_error (cairo_status_t status)
{
cairo_path_t *path;
/* special case NO_MEMORY so as to avoid allocations */
if (status == CAIRO_STATUS_NO_MEMORY)
return (cairo_path_t*) &_cairo_path_nil;
path = malloc (sizeof (cairo_path_t));
if (path == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
path->num_data = 0;
path->data = NULL;
path->status = status;
return path;
}
static cairo_path_t *
_cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
cairo_gstate_t *gstate,
cairo_bool_t flatten)
{
cairo_path_t *path;
path = malloc (sizeof (cairo_path_t));
if (path == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
path->num_data = _cairo_path_count (path, path_fixed,
_cairo_gstate_get_tolerance (gstate),
flatten);
if (path->num_data < 0) {
free (path);
return (cairo_path_t*) &_cairo_path_nil;
}
if (path->num_data) {
path->data = _cairo_malloc_ab (path->num_data,
sizeof (cairo_path_data_t));
if (path->data == NULL) {
free (path);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
path->status = _cairo_path_populate (path, path_fixed,
gstate, flatten);
} else {
path->data = NULL;
path->status = CAIRO_STATUS_SUCCESS;
}
return path;
}
/**
* cairo_path_destroy:
* @path: a path previously returned by either cairo_copy_path() or
* cairo_copy_path_flat().
*
* Immediately releases all memory associated with @path. After a call
* to cairo_path_destroy() the @path pointer is no longer valid and
* should not be used further.
*
* Note: cairo_path_destroy() should only be called with a
* pointer to a #cairo_path_t returned by a cairo function. Any path
* that is created manually (ie. outside of cairo) should be destroyed
* manually as well.
**/
void
cairo_path_destroy (cairo_path_t *path)
{
if (path == NULL || path == &_cairo_path_nil)
return;
if (path->data)
free (path->data);
free (path);
}
/**
* _cairo_path_create:
* @path: a fixed-point, device-space path to be converted and copied
* @gstate: the current graphics state
*
* Creates a user-space #cairo_path_t copy of the given device-space
* @path. The @gstate parameter provides the inverse CTM for the
* conversion.
*
* Return value: the new copy of the path. If there is insufficient
* memory a pointer to a special static nil #cairo_path_t will be
* returned instead with status==%CAIRO_STATUS_NO_MEMORY and
* data==%NULL.
**/
cairo_path_t *
_cairo_path_create (cairo_path_fixed_t *path,
cairo_gstate_t *gstate)
{
return _cairo_path_create_internal (path, gstate, FALSE);
}
/**
* _cairo_path_create_flat:
* @path: a fixed-point, device-space path to be flattened, converted and copied
* @gstate: the current graphics state
*
* Creates a flattened, user-space #cairo_path_t copy of the given
* device-space @path. The @gstate parameter provide the inverse CTM
* for the conversion, as well as the tolerance value to control the
* accuracy of the flattening.
*
* Return value: the flattened copy of the path. If there is insufficient
* memory a pointer to a special static nil #cairo_path_t will be
* returned instead with status==%CAIRO_STATUS_NO_MEMORY and
* data==%NULL.
**/
cairo_path_t *
_cairo_path_create_flat (cairo_path_fixed_t *path,
cairo_gstate_t *gstate)
{
return _cairo_path_create_internal (path, gstate, TRUE);
}
/**
* _cairo_path_append_to_context:
* @path: the path data to be appended
* @cr: a cairo context
*
* Append @path to the current path within @cr.
*
* Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
* is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
**/
cairo_status_t
_cairo_path_append_to_context (const cairo_path_t *path,
cairo_t *cr)
{
int i;
cairo_path_data_t *p;
cairo_status_t status;
for (i=0; i < path->num_data; i += path->data[i].header.length) {
p = &path->data[i];
switch (p->header.type) {
case CAIRO_PATH_MOVE_TO:
if (p->header.length < 2)
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_move_to (cr,
p[1].point.x, p[1].point.y);
break;
case CAIRO_PATH_LINE_TO:
if (p->header.length < 2)
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_line_to (cr,
p[1].point.x, p[1].point.y);
break;
case CAIRO_PATH_CURVE_TO:
if (p->header.length < 4)
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_curve_to (cr,
p[1].point.x, p[1].point.y,
p[2].point.x, p[2].point.y,
p[3].point.x, p[3].point.y);
break;
case CAIRO_PATH_CLOSE_PATH:
if (p->header.length < 1)
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_close_path (cr);
break;
default:
return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
}
status = cairo_status (cr);
if (status)
return status;
}
return CAIRO_STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,165 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2006 Red Hat, Inc
* Copyright © 2007 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
#ifndef CAIRO_PDF_OPERATORS_H
#define CAIRO_PDF_OPERATORS_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/* The glyph buffer size is based on the expected maximum glyphs in a
* line so that an entire line can be emitted in as one string. If the
* glyphs in a line exceeds this size the only downside is the slight
* overhead of emitting two strings.
*/
#define PDF_GLYPH_BUFFER_SIZE 200
typedef cairo_status_t (*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id,
unsigned int subset_id,
void *closure);
typedef struct _cairo_pdf_glyph {
unsigned int glyph_index;
double x_position;
double x_advance;
} cairo_pdf_glyph_t;
typedef struct _cairo_pdf_operators {
cairo_output_stream_t *stream;
cairo_matrix_t cairo_to_pdf;
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
cairo_bool_t in_text_object; /* inside BT/ET pair */
/* PDF text state */
cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */
unsigned int font_id;
unsigned int subset_id;
cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */
cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */
cairo_matrix_t font_matrix_inverse;
double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */
double cur_y;
int hex_width;
int num_glyphs;
cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE];
/* PDF line style */
cairo_bool_t has_line_style;
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
cairo_bool_t has_dashes;
} cairo_pdf_operators_t;
cairo_private void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
cairo_private cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
cairo_private void
_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators,
cairo_pdf_operators_use_font_subset_t use_font_subset,
void *closure);
cairo_private void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream);
cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
cairo_private cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
cairo_private void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators);
cairo_private cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale);
cairo_private cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font);
#endif /* CAIRO_PDF_OPERATORS_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,171 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
* Copyright © 2006 Red Hat, Inc
* Copyright © 2007, 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Kristian Høgsberg <krh@redhat.com>
* Carl Worth <cworth@cworth.org>
* Adrian Johnson <ajohnson@redneon.com>
*/
#ifndef CAIRO_PDF_SURFACE_PRIVATE_H
#define CAIRO_PDF_SURFACE_PRIVATE_H
#include "cairo-pdf.h"
#include "cairo-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-path-fixed-private.h"
typedef struct _cairo_pdf_resource {
unsigned int id;
} cairo_pdf_resource_t;
typedef struct _cairo_pdf_group_resources {
cairo_array_t alphas;
cairo_array_t smasks;
cairo_array_t patterns;
cairo_array_t xobjects;
cairo_array_t fonts;
} cairo_pdf_group_resources_t;
typedef struct _cairo_pdf_pattern {
double width;
double height;
cairo_pattern_t *pattern;
cairo_pdf_resource_t pattern_res;
cairo_pdf_resource_t gstate_res;
} cairo_pdf_pattern_t;
typedef enum _cairo_pdf_operation {
PDF_PAINT,
PDF_MASK,
PDF_FILL,
PDF_STROKE,
PDF_SHOW_GLYPHS
} cairo_pdf_operation_t;
typedef struct _cairo_pdf_smask_group
{
double width;
double height;
cairo_pdf_resource_t group_res;
cairo_pdf_operation_t operation;
cairo_pattern_t *source;
cairo_pdf_resource_t source_res;
cairo_pattern_t *mask;
cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule;
cairo_stroke_style_t *style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t cluster_flags;
cairo_scaled_font_t *scaled_font;
} cairo_pdf_smask_group_t;
typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
struct _cairo_pdf_surface {
cairo_surface_t base;
/* Prefer the name "output" here to avoid confusion over the
* structure within a PDF document known as a "stream". */
cairo_output_stream_t *output;
double width;
double height;
cairo_matrix_t cairo_to_pdf;
cairo_array_t objects;
cairo_array_t pages;
cairo_array_t rgb_linear_functions;
cairo_array_t alpha_linear_functions;
cairo_array_t patterns;
cairo_array_t smask_groups;
cairo_array_t knockout_group;
cairo_scaled_font_subsets_t *font_subsets;
cairo_array_t fonts;
cairo_pdf_resource_t next_available_resource;
cairo_pdf_resource_t pages_resource;
cairo_bool_t compress_content;
cairo_pdf_resource_t content;
cairo_pdf_resource_t content_resources;
cairo_pdf_group_resources_t resources;
cairo_bool_t has_fallback_images;
struct {
cairo_bool_t active;
cairo_pdf_resource_t self;
cairo_pdf_resource_t length;
long start_offset;
cairo_bool_t compressed;
cairo_output_stream_t *old_output;
} pdf_stream;
struct {
cairo_bool_t active;
cairo_output_stream_t *stream;
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *old_output;
cairo_pdf_resource_t resource;
cairo_bool_t is_knockout;
} group_stream;
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t select_pattern_gstate_saved;
cairo_bool_t force_fallbacks;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
cairo_surface_t *paginated_surface;
};
#endif /* CAIRO_PDF_SURFACE_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_PDF_H
#define CAIRO_PDF_H
#include "cairo.h"
#if CAIRO_HAS_PDF_SURFACE
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_pdf_surface_create (const char *filename,
double width_in_points,
double height_in_points);
cairo_public cairo_surface_t *
cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width_in_points,
double height_in_points);
cairo_public void
cairo_pdf_surface_set_size (cairo_surface_t *surface,
double width_in_points,
double height_in_points);
CAIRO_END_DECLS
#else /* CAIRO_HAS_PDF_SURFACE */
# error Cairo was not compiled with support for the pdf backend
#endif /* CAIRO_HAS_PDF_SURFACE */
#endif /* CAIRO_PDF_H */

View file

@ -0,0 +1,491 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
static int
_cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix);
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
double tolerance,
cairo_matrix_t *ctm)
{
int i;
int reflect;
pen->radius = radius;
pen->tolerance = tolerance;
reflect = _cairo_matrix_compute_determinant (ctm) < 0.;
pen->num_vertices = _cairo_pen_vertices_needed (tolerance,
radius,
ctm);
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
pen->vertices = pen->vertices_embedded;
}
/*
* Compute pen coordinates. To generate the right ellipse, compute points around
* a circle in user space and transform them to device space. To get a consistent
* orientation in device space, flip the pen if the transformation matrix
* is reflecting
*/
for (i=0; i < pen->num_vertices; i++) {
double theta = 2 * M_PI * i / (double) pen->num_vertices;
double dx = radius * cos (reflect ? -theta : theta);
double dy = radius * sin (reflect ? -theta : theta);
cairo_pen_vertex_t *v = &pen->vertices[i];
cairo_matrix_transform_distance (ctm, &dx, &dy);
v->point.x = _cairo_fixed_from_double (dx);
v->point.y = _cairo_fixed_from_double (dy);
}
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
void
_cairo_pen_fini (cairo_pen_t *pen)
{
if (pen->vertices != pen->vertices_embedded)
free (pen->vertices);
pen->vertices = pen->vertices_embedded;
pen->num_vertices = 0;
}
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
*pen = *other;
pen->vertices = pen->vertices_embedded;
if (pen->num_vertices) {
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (pen->vertices, other->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
}
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
{
cairo_status_t status;
int num_vertices;
int i;
num_vertices = pen->num_vertices + num_points;
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
pen->vertices != pen->vertices_embedded)
{
cairo_pen_vertex_t *vertices;
if (pen->vertices == pen->vertices_embedded) {
vertices = _cairo_malloc_ab (num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (vertices, pen->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
} else {
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pen->vertices = vertices;
}
pen->num_vertices = num_vertices;
/* initialize new vertices */
for (i=0; i < num_points; i++)
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
status = _cairo_hull_compute (pen->vertices, &pen->num_vertices);
if (status)
return status;
_cairo_pen_compute_slopes (pen);
return CAIRO_STATUS_SUCCESS;
}
/*
The circular pen in user space is transformed into an ellipse in
device space.
We construct the pen by computing points along the circumference
using equally spaced angles.
We show that this approximation to the ellipse has maximum error at the
major axis of the ellipse.
Set
M = major axis length
m = minor axis length
Align 'M' along the X axis and 'm' along the Y axis and draw
an ellipse parameterized by angle 't':
x = M cos t y = m sin t
Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
The distance from the average of these two points to (x,y) represents
the maximum error in approximating the ellipse with a polygon formed
from vertices 2∆ radians apart.
x+ = M cos (t+∆) y+ = m sin (t+∆)
x- = M cos (t-∆) y- = m sin (t-∆)
Now compute the approximation error, E:
Ex = (x - (x+ + x-) / 2)
Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
= M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
cos(t)cos(∆) - sin(t)sin(∆))/2)
= M(cos(t) - cos(t)cos(∆))
= M cos(t) (1 - cos(∆))
Ey = y - (y+ - y-) / 2
= m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
= m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
sin(t)cos(∆) - cos(t)sin(∆))/2)
= m (sin(t) - sin(t)cos(∆))
= m sin(t) (1 - cos(∆))
E² = Ex² + Ey²
= (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
= (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
= (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
= (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
Find the extremum by differentiation wrt t and setting that to zero
∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
0 = 2 cos (t) sin (t)
0 = sin (2t)
t = nπ
Which is to say that the maximum and minimum errors occur on the
axes of the ellipse at 0 and π radians:
E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
= (1-cos(∆))² M²
E²(π) = (1-cos(∆))² m²
maximum error = M (1-cos(∆))
minimum error = m (1-cos(∆))
We must make maximum error ≤ tolerance, so compute the ∆ needed:
tolerance = M (1-cos(∆))
tolerance / M = 1 - cos (∆)
cos(∆) = 1 - tolerance/M
∆ = acos (1 - tolerance / M);
Remembering that ∆ is half of our angle between vertices,
the number of vertices is then
vertices = ceil(2π/2∆).
= ceil(π/∆).
Note that this also equation works for M == m (a circle) as it
doesn't matter where on the circle the error is computed.
*/
static int
_cairo_pen_vertices_needed (double tolerance,
double radius,
cairo_matrix_t *matrix)
{
/*
* the pen is a circle that gets transformed to an ellipse by matrix.
* compute major axis length for a pen with the specified radius.
* we don't need the minor axis length.
*/
double major_axis = _cairo_matrix_transformed_circle_major_axis(matrix, radius);
/*
* compute number of vertices needed
*/
int num_vertices;
/* Where tolerance / M is > 1, we use 4 points */
if (tolerance >= major_axis) {
num_vertices = 4;
} else {
double delta = acos (1 - tolerance / major_axis);
num_vertices = ceil (M_PI / delta);
/* number of vertices must be even */
if (num_vertices % 2)
num_vertices++;
/* And we must always have at least 4 vertices. */
if (num_vertices < 4)
num_vertices = 4;
}
return num_vertices;
}
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen)
{
int i, i_prev;
cairo_pen_vertex_t *prev, *v, *next;
for (i=0, i_prev = pen->num_vertices - 1;
i < pen->num_vertices;
i_prev = i++) {
prev = &pen->vertices[i_prev];
v = &pen->vertices[i];
next = &pen->vertices[(i + 1) % pen->num_vertices];
_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
}
}
/*
* Find active pen vertex for clockwise edge of stroke at the given slope.
*
* The strictness of the inequalities here is delicate. The issue is
* that the slope_ccw member of one pen vertex will be equivalent to
* the slope_cw member of the next pen vertex in a counterclockwise
* order. However, for this function, we care strongly about which
* vertex is returned.
*
* [I think the "care strongly" above has to do with ensuring that the
* pen's "extra points" from the spline's initial and final slopes are
* properly found when beginning the spline stroking.]
*/
void
_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active)
{
int i;
for (i=0; i < pen->num_vertices; i++) {
if ((_cairo_slope_compare (slope, &pen->vertices[i].slope_ccw) < 0) &&
(_cairo_slope_compare (slope, &pen->vertices[i].slope_cw) >= 0))
break;
}
/* If the desired slope cannot be found between any of the pen
* vertices, then we must have a degenerate pen, (such as a pen
* that's been transformed to a line). In that case, we consider
* the first pen vertex as the appropriate clockwise vertex.
*/
if (i == pen->num_vertices)
i = 0;
*active = i;
}
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
*
* Note: See the comments for _cairo_pen_find_active_cw_vertex_index
* for some details about the strictness of the inequalities here.
*/
void
_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
cairo_slope_t *slope,
int *active)
{
int i;
cairo_slope_t slope_reverse;
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
slope_reverse.dy = -slope_reverse.dy;
for (i=pen->num_vertices-1; i >= 0; i--) {
if ((_cairo_slope_compare (&pen->vertices[i].slope_ccw, &slope_reverse) >= 0) &&
(_cairo_slope_compare (&pen->vertices[i].slope_cw, &slope_reverse) < 0))
break;
}
/* If the desired slope cannot be found between any of the pen
* vertices, then we must have a degenerate pen, (such as a pen
* that's been transformed to a line). In that case, we consider
* the last pen vertex as the appropriate counterclockwise vertex.
*/
if (i < 0)
i = pen->num_vertices - 1;
*active = i;
}
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
cairo_spline_t *spline,
cairo_direction_t dir,
cairo_polygon_t *polygon)
{
int i;
int start, stop, step;
int active = 0;
cairo_point_t hull_point;
cairo_slope_t slope, initial_slope, final_slope;
cairo_point_t *point = spline->points;
int num_points = spline->num_points;
if (dir == CAIRO_DIRECTION_FORWARD) {
start = 0;
stop = num_points;
step = 1;
initial_slope = spline->initial_slope;
final_slope = spline->final_slope;
} else {
start = num_points - 1;
stop = -1;
step = -1;
initial_slope = spline->final_slope;
initial_slope.dx = -initial_slope.dx;
initial_slope.dy = -initial_slope.dy;
final_slope = spline->initial_slope;
final_slope.dx = -final_slope.dx;
final_slope.dy = -final_slope.dy;
}
_cairo_pen_find_active_cw_vertex_index (pen,
&initial_slope,
&active);
i = start;
while (i != stop) {
hull_point.x = point[i].x + pen->vertices[active].point.x;
hull_point.y = point[i].y + pen->vertices[active].point.y;
_cairo_polygon_line_to (polygon, &hull_point);
if (i + step == stop)
slope = final_slope;
else
_cairo_slope_init (&slope, &point[i], &point[i+step]);
/* The strict inequalities here ensure that if a spline slope
* compares identically with either of the slopes of the
* active vertex, then it remains the active vertex. This is
* very important since otherwise we can trigger an infinite
* loop in the case of a degenerate pen, (a line), where
* neither vertex considers itself active for the slope---one
* will consider it as equal and reject, and the other will
* consider it unequal and reject. This is due to the inherent
* ambiguity when comparing slopes that differ by exactly
* pi. */
if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) {
if (++active == pen->num_vertices)
active = 0;
} else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) {
if (--active == -1)
active = pen->num_vertices - 1;
} else {
i += step;
}
}
}
/* Compute outline of a given spline using the pen.
The trapezoids needed to fill that outline will be added to traps
*/
cairo_status_t
_cairo_pen_stroke_spline (cairo_pen_t *pen,
cairo_spline_t *spline,
double tolerance,
cairo_traps_t *traps)
{
cairo_status_t status;
cairo_polygon_t polygon;
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
if (pen->num_vertices <= 1)
return CAIRO_STATUS_SUCCESS;
_cairo_polygon_init (&polygon);
status = _cairo_spline_decompose (spline, tolerance);
if (status)
goto BAIL;
_cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
_cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
_cairo_polygon_close (&polygon);
status = _cairo_polygon_status (&polygon);
if (status)
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
BAIL:
_cairo_polygon_fini (&polygon);
return status;
}

View file

@ -0,0 +1,708 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include <errno.h>
#include <png.h>
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
static void
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *b = &data[i];
uint32_t pixel;
uint8_t alpha;
memcpy (&pixel, b, sizeof (uint32_t));
alpha = (pixel & 0xff000000) >> 24;
if (alpha == 0) {
b[0] = b[1] = b[2] = b[3] = 0;
} else {
b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
}
/* Converts native endian xRGB => RGBx bytes */
static void
convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *b = &data[i];
uint32_t pixel;
memcpy (&pixel, b, sizeof (uint32_t));
b[0] = (pixel & 0xff0000) >> 16;
b[1] = (pixel & 0x00ff00) >> 8;
b[2] = (pixel & 0x0000ff) >> 0;
b[3] = 0;
}
}
/* Use a couple of simple error callbacks that do not print anything to
* stderr and rely on the user to check for errors via the #cairo_status_t
* return.
*/
static void
png_simple_error_callback (png_structp png,
png_const_charp error_msg)
{
cairo_status_t *error = png_get_error_ptr (png);
/* default to the most likely error */
if (*error == CAIRO_STATUS_SUCCESS)
*error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
#ifdef PNG_SETJMP_SUPPORTED
longjmp (png_jmpbuf (png), 1);
#endif
/* if we get here, then we have to choice but to abort ... */
}
static void
png_simple_warning_callback (png_structp png,
png_const_charp error_msg)
{
cairo_status_t *error = png_get_error_ptr (png);
/* default to the most likely error */
if (*error == CAIRO_STATUS_SUCCESS)
*error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* png does not expect to abort and will try to tidy up after a warning */
}
/* Starting with libpng-1.2.30, we must explicitly specify an output_flush_fn.
* Otherwise, we will segfault if we are writing to a stream. */
static void
png_simple_output_flush_fn (png_structp png_ptr)
{
}
static cairo_status_t
write_png (cairo_surface_t *surface,
png_rw_ptr write_func,
void *closure)
{
int i;
cairo_status_t status;
cairo_image_surface_t *image;
void *image_extra;
png_struct *png;
png_info *info;
png_byte **volatile rows = NULL;
png_color_16 white;
int png_color_type;
int depth;
status = _cairo_surface_acquire_source_image (surface,
&image,
&image_extra);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
else if (status)
return status;
/* PNG complains about "Image width or height is zero in IHDR" */
if (image->width == 0 || image->height == 0) {
status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
goto BAIL1;
}
rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
if (rows == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL1;
}
for (i = 0; i < image->height; i++)
rows[i] = (png_byte *) image->data + i * image->stride;
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
png_simple_warning_callback);
if (png == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
info = png_create_info_struct (png);
if (info == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL3;
}
#ifdef PNG_SETJMP_SUPPORTED
if (setjmp (png_jmpbuf (png)))
goto BAIL3;
#endif
png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
switch (image->format) {
case CAIRO_FORMAT_ARGB32:
depth = 8;
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
case CAIRO_FORMAT_RGB24:
depth = 8;
png_color_type = PNG_COLOR_TYPE_RGB;
break;
case CAIRO_FORMAT_A8:
depth = 8;
png_color_type = PNG_COLOR_TYPE_GRAY;
break;
case CAIRO_FORMAT_A1:
depth = 1;
png_color_type = PNG_COLOR_TYPE_GRAY;
#ifndef WORDS_BIGENDIAN
png_set_packswap (png);
#endif
break;
default:
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL3;
}
png_set_IHDR (png, info,
image->width,
image->height, depth,
png_color_type,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
white.gray = (1 << depth) - 1;
white.red = white.blue = white.green = white.gray;
png_set_bKGD (png, info, &white);
if (0) { /* XXX extract meta-data from surface (i.e. creation date) */
png_time pt;
png_convert_from_time_t (&pt, time (NULL));
png_set_tIME (png, info, &pt);
}
/* We have to call png_write_info() before setting up the write
* transformation, since it stores data internally in 'png'
* that is needed for the write transformation functions to work.
*/
png_write_info (png, info);
if (image->format == CAIRO_FORMAT_ARGB32)
png_set_write_user_transform_fn (png, unpremultiply_data);
else if (image->format == CAIRO_FORMAT_RGB24)
png_set_write_user_transform_fn (png, convert_data_to_bytes);
if (image->format == CAIRO_FORMAT_RGB24)
png_set_filler (png, 0, PNG_FILLER_AFTER);
png_write_image (png, rows);
png_write_end (png, info);
BAIL3:
png_destroy_write_struct (&png, &info);
BAIL2:
free (rows);
BAIL1:
_cairo_surface_release_source_image (surface, image, image_extra);
return status;
}
static void
stdio_write_func (png_structp png, png_bytep data, png_size_t size)
{
FILE *fp;
fp = png_get_io_ptr (png);
while (size) {
size_t ret = fwrite (data, 1, size, fp);
size -= ret;
data += ret;
if (size && ferror (fp)) {
cairo_status_t *error = png_get_error_ptr (png);
if (*error == CAIRO_STATUS_SUCCESS)
*error = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
png_error (png, NULL);
}
}
}
/**
* cairo_surface_write_to_png:
* @surface: a #cairo_surface_t with pixel contents
* @filename: the name of a file to write to
*
* Writes the contents of @surface to a new file @filename as a PNG
* image.
*
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
* be allocated for the operation or
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
* while attempting to write the file.
**/
cairo_status_t
cairo_surface_write_to_png (cairo_surface_t *surface,
const char *filename)
{
FILE *fp;
cairo_status_t status;
if (surface->status)
return surface->status;
if (surface->finished)
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
fp = fopen (filename, "wb");
if (fp == NULL) {
switch (errno) {
case ENOMEM:
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
default:
return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
}
}
status = write_png (surface, stdio_write_func, fp);
if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
return status;
}
struct png_write_closure_t {
cairo_write_func_t write_func;
void *closure;
};
static void
stream_write_func (png_structp png, png_bytep data, png_size_t size)
{
cairo_status_t status;
struct png_write_closure_t *png_closure;
png_closure = png_get_io_ptr (png);
status = png_closure->write_func (png_closure->closure, data, size);
if (status) {
cairo_status_t *error = png_get_error_ptr (png);
if (*error == CAIRO_STATUS_SUCCESS)
*error = status;
png_error (png, NULL);
}
}
/**
* cairo_surface_write_to_png_stream:
* @surface: a #cairo_surface_t with pixel contents
* @write_func: a #cairo_write_func_t
* @closure: closure data for the write function
*
* Writes the image surface to the write function.
*
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
* memory could not be allocated for the operation,
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents.
**/
cairo_status_t
cairo_surface_write_to_png_stream (cairo_surface_t *surface,
cairo_write_func_t write_func,
void *closure)
{
struct png_write_closure_t png_closure;
if (surface->status)
return surface->status;
if (surface->finished)
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
png_closure.write_func = write_func;
png_closure.closure = closure;
return write_png (surface, stream_write_func, &png_closure);
}
slim_hidden_def (cairo_surface_write_to_png_stream);
static inline int
multiply_alpha (int alpha, int color)
{
int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}
/* Premultiplies data and converts RGBA bytes => native endian */
static void
premultiply_data (png_structp png,
png_row_infop row_info,
png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *base = &data[i];
uint8_t alpha = base[3];
uint32_t p;
if (alpha == 0) {
p = 0;
} else {
uint8_t red = base[0];
uint8_t green = base[1];
uint8_t blue = base[2];
if (alpha != 0xff) {
red = multiply_alpha (alpha, red);
green = multiply_alpha (alpha, green);
blue = multiply_alpha (alpha, blue);
}
p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
}
memcpy (base, &p, sizeof (uint32_t));
}
}
/* Converts RGBx bytes to native endian xRGB */
static void
convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4) {
uint8_t *base = &data[i];
uint8_t red = base[0];
uint8_t green = base[1];
uint8_t blue = base[2];
uint32_t pixel;
pixel = (0xff << 24) | (red << 16) | (green << 8) | (blue << 0);
memcpy (base, &pixel, sizeof (uint32_t));
}
}
static cairo_surface_t *
read_png (png_rw_ptr read_func,
void *closure)
{
cairo_surface_t *surface;
png_struct *png = NULL;
png_info *info;
png_byte *data = NULL;
png_byte **row_pointers = NULL;
png_uint_32 png_width, png_height;
int depth, color_type, interlace, stride;
unsigned int i;
cairo_format_t format;
cairo_status_t status;
/* XXX: Perhaps we'll want some other error handlers? */
png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
&status,
png_simple_error_callback,
png_simple_warning_callback);
if (png == NULL) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
info = png_create_info_struct (png);
if (info == NULL) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
png_set_read_fn (png, closure, read_func);
status = CAIRO_STATUS_SUCCESS;
#ifdef PNG_SETJMP_SUPPORTED
if (setjmp (png_jmpbuf (png))) {
surface = _cairo_surface_create_in_error (status);
goto BAIL;
}
#endif
png_read_info (png, info);
png_get_IHDR (png, info,
&png_width, &png_height, &depth,
&color_type, &interlace, NULL, NULL);
if (status) { /* catch any early warnings */
surface = _cairo_surface_create_in_error (status);
goto BAIL;
}
/* convert palette/gray image to rgb */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb (png);
/* expand gray bit depth if needed */
if (color_type == PNG_COLOR_TYPE_GRAY) {
#if PNG_LIBPNG_VER >= 10209
png_set_expand_gray_1_2_4_to_8 (png);
#else
png_set_gray_1_2_4_to_8 (png);
#endif
}
/* transform transparency to alpha */
if (png_get_valid (png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png);
if (depth == 16)
png_set_strip_16 (png);
if (depth < 8)
png_set_packing (png);
/* convert grayscale to RGB */
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_gray_to_rgb (png);
}
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling (png);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
/* recheck header after setting EXPAND options */
png_read_update_info (png, info);
png_get_IHDR (png, info,
&png_width, &png_height, &depth,
&color_type, &interlace, NULL, NULL);
if (depth != 8 ||
! (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
{
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
goto BAIL;
}
switch (color_type) {
default:
ASSERT_NOT_REACHED;
/* fall-through just in case ;-) */
case PNG_COLOR_TYPE_RGB_ALPHA:
format = CAIRO_FORMAT_ARGB32;
png_set_read_user_transform_fn (png, premultiply_data);
break;
case PNG_COLOR_TYPE_RGB:
format = CAIRO_FORMAT_RGB24;
png_set_read_user_transform_fn (png, convert_bytes_to_data);
break;
}
stride = cairo_format_stride_for_width (format, png_width);
if (stride < 0) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
goto BAIL;
}
data = _cairo_malloc_ab (png_height, stride);
if (data == NULL) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
if (row_pointers == NULL) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
for (i = 0; i < png_height; i++)
row_pointers[i] = &data[i * stride];
png_read_image (png, row_pointers);
png_read_end (png, info);
if (status) { /* catch any late warnings - probably hit an error already */
surface = _cairo_surface_create_in_error (status);
goto BAIL;
}
surface = cairo_image_surface_create_for_data (data, format,
png_width, png_height,
stride);
if (surface->status)
goto BAIL;
_cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
data = NULL;
BAIL:
if (row_pointers)
free (row_pointers);
if (data)
free (data);
if (png)
png_destroy_read_struct (&png, &info, NULL);
return surface;
}
static void
stdio_read_func (png_structp png, png_bytep data, png_size_t size)
{
FILE *fp;
fp = png_get_io_ptr (png);
while (size) {
size_t ret = fread (data, 1, size, fp);
size -= ret;
data += ret;
if (size && (feof (fp) || ferror (fp))) {
cairo_status_t *error = png_get_error_ptr (png);
if (*error == CAIRO_STATUS_SUCCESS)
*error = _cairo_error (CAIRO_STATUS_READ_ERROR);
png_error (png, NULL);
}
}
}
/**
* cairo_image_surface_create_from_png:
* @filename: name of PNG file to load
*
* Creates a new image surface and initializes the contents to the
* given PNG file.
*
* Return value: a new #cairo_surface_t initialized with the contents
* of the PNG file, or a "nil" surface if any error occurred. A nil
* surface can be checked for with cairo_surface_status(surface) which
* may return one of the following values:
*
* %CAIRO_STATUS_NO_MEMORY
* %CAIRO_STATUS_FILE_NOT_FOUND
* %CAIRO_STATUS_READ_ERROR
**/
cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)
{
FILE *fp;
cairo_surface_t *surface;
fp = fopen (filename, "rb");
if (fp == NULL) {
cairo_status_t status;
switch (errno) {
case ENOMEM:
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break;
case ENOENT:
status = _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND);
break;
default:
status = _cairo_error (CAIRO_STATUS_READ_ERROR);
break;
}
return _cairo_surface_create_in_error (status);
}
surface = read_png (stdio_read_func, fp);
fclose (fp);
return surface;
}
struct png_read_closure_t {
cairo_read_func_t read_func;
void *closure;
};
static void
stream_read_func (png_structp png, png_bytep data, png_size_t size)
{
cairo_status_t status;
struct png_read_closure_t *png_closure;
png_closure = png_get_io_ptr (png);
status = png_closure->read_func (png_closure->closure, data, size);
if (status) {
cairo_status_t *error = png_get_error_ptr (png);
if (*error == CAIRO_STATUS_SUCCESS)
*error = status;
png_error (png, NULL);
}
}
/**
* cairo_image_surface_create_from_png_stream:
* @read_func: function called to read the data of the file
* @closure: data to pass to @read_func.
*
* Creates a new image surface from PNG data read incrementally
* via the @read_func function.
*
* Return value: a new #cairo_surface_t initialized with the contents
* of the PNG file or %NULL if the data read is not a valid PNG image or
* memory could not be allocated for the operation.
**/
cairo_surface_t *
cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
void *closure)
{
struct png_read_closure_t png_closure;
png_closure.read_func = read_func;
png_closure.closure = closure;
return read_png (stream_read_func, &png_closure);
}

View file

@ -0,0 +1,149 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#include "cairoint.h"
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
polygon->status = CAIRO_STATUS_SUCCESS;
polygon->num_edges = 0;
polygon->edges = polygon->edges_embedded;
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
polygon->has_current_point = FALSE;
}
void
_cairo_polygon_fini (cairo_polygon_t *polygon)
{
if (polygon->edges != polygon->edges_embedded)
free (polygon->edges);
}
/* make room for at least one more edge */
static cairo_bool_t
_cairo_polygon_grow (cairo_polygon_t *polygon)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int new_size = 4 * old_size;
if (polygon->edges == polygon->edges_embedded) {
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
if (new_edges != NULL)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else {
new_edges = _cairo_realloc_ab (polygon->edges,
new_size, sizeof (cairo_edge_t));
}
if (new_edges == NULL) {
polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
polygon->edges = new_edges;
polygon->edges_size = new_size;
return TRUE;
}
static void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
const cairo_point_t *p2)
{
cairo_edge_t *edge;
/* drop horizontal edges */
if (p1->y == p2->y)
goto DONE;
if (polygon->num_edges == polygon->edges_size) {
if (! _cairo_polygon_grow (polygon))
return;
}
edge = &polygon->edges[polygon->num_edges++];
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
edge->clockWise = 1;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
edge->clockWise = 0;
}
DONE:
_cairo_polygon_move_to (polygon, p2);
}
void
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (! polygon->has_current_point)
polygon->first_point = *point;
polygon->current_point = *point;
polygon->has_current_point = TRUE;
}
void
_cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (polygon->has_current_point)
_cairo_polygon_add_edge (polygon, &polygon->current_point, point);
else
_cairo_polygon_move_to (polygon, point);
}
void
_cairo_polygon_close (cairo_polygon_t *polygon)
{
if (polygon->has_current_point) {
_cairo_polygon_add_edge (polygon,
&polygon->current_point,
&polygon->first_point);
polygon->has_current_point = FALSE;
}
}

View file

@ -0,0 +1,57 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Red Hat, Inc.
*
* Contributor(s):
* Carl D. Worth <cworth@redhat.com>
*/
#ifndef CAIRO_PRIVATE_H
#define CAIRO_PRIVATE_H
#include "cairo-reference-count-private.h"
#include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h"
struct _cairo {
cairo_reference_count_t ref_count;
cairo_status_t status;
cairo_user_data_array_t user_data;
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[1];
cairo_gstate_t *gstate_freelist;
cairo_path_fixed_t path[1];
};
#endif /* CAIRO_PRIVATE_H */

View file

@ -0,0 +1,100 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
* Copyright © 2005 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com>
* Keith Packard <keithp@keithp.com>
*/
#ifndef CAIRO_PS_SURFACE_PRIVATE_H
#define CAIRO_PS_SURFACE_PRIVATE_H
#include "cairo-ps.h"
#include "cairo-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include <time.h>
typedef struct cairo_ps_surface {
cairo_surface_t base;
/* Here final_stream corresponds to the stream/file passed to
* cairo_ps_surface_create surface is built. Meanwhile stream is a
* temporary stream in which the file output is built, (so that
* the header can be built and inserted into the target stream
* before the contents of the temporary stream are copied). */
cairo_output_stream_t *final_stream;
FILE *tmpfile;
cairo_output_stream_t *stream;
cairo_bool_t eps;
cairo_content_t content;
double width;
double height;
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
cairo_image_surface_t *image;
void *image_extra;
cairo_bool_t use_string_datasource;
cairo_bool_t current_pattern_is_solid_color;
cairo_color_t current_color;
int num_pages;
cairo_paginated_mode_t paginated_mode;
cairo_bool_t force_fallbacks;
cairo_bool_t has_creation_date;
time_t creation_date;
cairo_scaled_font_subsets_t *font_subsets;
cairo_array_t dsc_header_comments;
cairo_array_t dsc_setup_comments;
cairo_array_t dsc_page_setup_comments;
cairo_array_t *dsc_comment_target;
cairo_ps_level_t ps_level;
cairo_ps_level_t ps_level_used;
cairo_pdf_operators_t pdf_operators;
cairo_surface_t *paginated_surface;
} cairo_ps_surface_t;
#endif /* CAIRO_PS_SURFACE_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_PS_H
#define CAIRO_PS_H
#include "cairo.h"
#if CAIRO_HAS_PS_SURFACE
#include <stdio.h>
CAIRO_BEGIN_DECLS
/* PS-surface functions */
/**
* cairo_ps_level_t:
* @CAIRO_PS_LEVEL_2: The language level 2 of the PostScript specification.
* @CAIRO_PS_LEVEL_3: The language level 3 of the PostScript specification.
*
* #cairo_ps_level_t is used to describe the language level of the
* PostScript Language Reference that a generated PostScript file will
* conform to.
*/
typedef enum _cairo_ps_level {
CAIRO_PS_LEVEL_2,
CAIRO_PS_LEVEL_3
} cairo_ps_level_t;
cairo_public cairo_surface_t *
cairo_ps_surface_create (const char *filename,
double width_in_points,
double height_in_points);
cairo_public cairo_surface_t *
cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
void *closure,
double width_in_points,
double height_in_points);
cairo_public void
cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
cairo_ps_level_t level);
cairo_public void
cairo_ps_get_levels (cairo_ps_level_t const **levels,
int *num_levels);
cairo_public const char *
cairo_ps_level_to_string (cairo_ps_level_t level);
cairo_public void
cairo_ps_surface_set_eps (cairo_surface_t *surface,
cairo_bool_t eps);
cairo_public cairo_bool_t
cairo_ps_surface_get_eps (cairo_surface_t *surface);
cairo_public void
cairo_ps_surface_set_size (cairo_surface_t *surface,
double width_in_points,
double height_in_points);
cairo_public void
cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
const char *comment);
cairo_public void
cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface);
cairo_public void
cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_PS_SURFACE */
# error Cairo was not compiled with support for the ps backend
#endif /* CAIRO_HAS_PS_SURFACE */
#endif /* CAIRO_PS_H */

View file

@ -0,0 +1,840 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright <EFBFBD> 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#include "cairoint.h"
#include <dlfcn.h>
#include "cairo-quartz.h"
#include "cairo-quartz-private.h"
/* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
/* These aren't public before 10.5, and some have different names in 10.4 */
static int (*CGFontGetUnitsPerEmPtr) (CGFontRef) = NULL;
static bool (*CGFontGetGlyphAdvancesPtr) (CGFontRef, const CGGlyph[], size_t, int[]) = NULL;
static bool (*CGFontGetGlyphBBoxesPtr) (CGFontRef, const CGGlyph[], size_t, CGRect[]) = NULL;
static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL;
/* Not public, but present */
static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL;
/* Not public in the least bit */
static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
/* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
typedef struct {
int ascent;
int descent;
int leading;
} quartz_CGFontMetrics;
static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
static void
quartz_font_ensure_symbols(void)
{
if (_cairo_quartz_font_symbol_lookup_done)
return;
/* Look for the 10.5 versions first */
CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
if (!CGFontGetGlyphBBoxesPtr)
CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
if (!CGFontGetGlyphsForUnicharsPtr)
CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
/* We just need one of these two */
CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
/* These have the same name in 10.4 and 10.5 */
CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
CGFontGetGlyphBBoxesPtr &&
CGFontGetGlyphsForUnicharsPtr &&
CGFontGetUnitsPerEmPtr &&
CGFontGetGlyphAdvancesPtr &&
CGFontGetGlyphPathPtr &&
(CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
_cairo_quartz_font_symbols_present = TRUE;
_cairo_quartz_font_symbol_lookup_done = TRUE;
}
typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
struct _cairo_quartz_scaled_font {
cairo_scaled_font_t base;
};
struct _cairo_quartz_font_face {
cairo_font_face_t base;
CGFontRef cgFont;
};
/*
* font face backend
*/
static void
_cairo_quartz_font_face_destroy (void *abstract_face)
{
cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
CGFontRelease (font_face->cgFont);
}
static cairo_status_t
_cairo_quartz_font_face_scaled_font_create (void *abstract_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **font_out)
{
cairo_quartz_font_face_t *font_face = abstract_face;
cairo_quartz_scaled_font_t *font = NULL;
cairo_status_t status;
cairo_font_extents_t fs_metrics;
double ems;
CGRect bbox;
quartz_font_ensure_symbols();
if (!_cairo_quartz_font_symbols_present)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font = malloc(sizeof(cairo_quartz_scaled_font_t));
if (font == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memset (font, 0, sizeof(cairo_quartz_scaled_font_t));
status = _cairo_scaled_font_init (&font->base,
&font_face->base, font_matrix, ctm, options,
&_cairo_quartz_scaled_font_backend);
if (status)
goto FINISH;
ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
/* initialize metrics */
if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) {
fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems);
fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems);
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
(CGFontGetLeadingPtr (font_face->cgFont) / ems);
bbox = CGFontGetFontBBoxPtr (font_face->cgFont);
fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
fs_metrics.max_y_advance = 0.0;
} else {
CGGlyph wGlyph;
UniChar u;
quartz_CGFontMetrics *m;
m = CGFontGetHMetricsPtr (font_face->cgFont);
/* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
if (!m) {
status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
goto FINISH;
}
fs_metrics.ascent = (m->ascent / ems);
fs_metrics.descent = - (m->descent / ems);
fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems);
/* We kind of have to guess here; W's big, right? */
u = (UniChar) 'W';
CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1);
if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) {
fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
fs_metrics.max_y_advance = 0.0;
} else {
fs_metrics.max_x_advance = 0.0;
fs_metrics.max_y_advance = 0.0;
}
}
status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
FINISH:
if (status != CAIRO_STATUS_SUCCESS) {
free (font);
} else {
*font_out = (cairo_scaled_font_t*) font;
}
return status;
}
static const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
CAIRO_FONT_TYPE_QUARTZ,
_cairo_quartz_font_face_destroy,
NULL, /* direct implementation */
_cairo_quartz_font_face_scaled_font_create
};
/**
* cairo_quartz_font_face_create_for_cgfont
* @font: a #CGFontRef obtained through a method external to cairo.
*
* Creates a new font for the Quartz font backend based on a
* #CGFontRef. This font can then be used with
* cairo_set_font_face() or cairo_scaled_font_create().
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.6
*/
cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
{
cairo_quartz_font_face_t *font_face;
quartz_font_ensure_symbols();
font_face = malloc (sizeof (cairo_quartz_font_face_t));
if (!font_face) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
font_face->cgFont = CGFontRetain (font);
_cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
return &font_face->base;
}
/*
* scaled font backend
*/
static cairo_quartz_font_face_t *
_cairo_quartz_scaled_to_face (void *abstract_font)
{
cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (&sfont->base);
if (!font_face || font_face->backend->type != CAIRO_FONT_TYPE_QUARTZ)
return NULL;
return (cairo_quartz_font_face_t*) font_face;
}
static cairo_status_t
_cairo_quartz_font_get_implementation (cairo_toy_font_face_t *toy_face,
cairo_scaled_font_t **font_face_out)
{
static cairo_user_data_key_t impl_font_face_key;
cairo_font_face_t *face;
cairo_status_t status;
const char *family = toy_face->family;
char *full_name = malloc(strlen(family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
CFStringRef cgFontName = NULL;
CGFontRef cgFont = NULL;
int loop;
face = cairo_font_face_get_user_data (&toy_face->base,
&impl_font_face_key);
if (face) {
*font_face_out = face;
return CAIRO_STATUS_SUCCESS;
}
quartz_font_ensure_symbols();
if (! _cairo_quartz_font_symbols_present)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* handle CSS-ish faces */
if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
family = "Times";
else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
family = "Helvetica";
else if (!strcmp(family, "cursive"))
family = "Apple Chancery";
else if (!strcmp(family, "fantasy"))
family = "Papyrus";
else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
family = "Courier";
/* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
* then drop the bold, then drop the slant, then drop both.. finally
* just use "Helvetica". And if Helvetica doesn't exist, give up.
*/
for (loop = 0; loop < 5; loop++) {
if (loop == 4)
family = "Helvetica";
strcpy (full_name, family);
if (loop < 3 && (loop & 1) == 0) {
if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
strcat (full_name, " Bold");
}
if (loop < 3 && (loop & 2) == 0) {
if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
strcat (full_name, " Italic");
else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
strcat (full_name, " Oblique");
}
if (CGFontCreateWithFontNamePtr) {
cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
cgFont = CGFontCreateWithFontNamePtr (cgFontName);
CFRelease (cgFontName);
} else {
cgFont = CGFontCreateWithNamePtr (full_name);
}
if (cgFont)
break;
}
if (!cgFont) {
/* Give up */
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
face = cairo_quartz_font_face_create_for_cgfont (cgFont);
CGFontRelease (cgFont);
if (face->status)
return face->status;
status = cairo_font_face_set_user_data (&toy_face->base,
&impl_font_face_key,
face,
(cairo_destroy_func_t) cairo_font_face_destroy);
if (status) {
cairo_font_face_destroy (face);
return status;
}
*font_face_out = face;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_quartz_font_create_toy (cairo_toy_font_face_t *toy_face,
const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm,
const cairo_font_options_t *options,
cairo_scaled_font_t **font_out)
{
cairo_font_face_t *face;
cairo_scaled_font_t *scaled_font;
cairo_status_t status;
status = _cairo_quartz_font_get_implementation (toy_face, &face);
if (status)
return status;
status = _cairo_quartz_font_face_scaled_font_create (face,
font_matrix, ctm,
options,
&scaled_font);
cairo_font_face_destroy (face);
if (status)
return status;
*font_out = scaled_font;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_quartz_font_fini(void *abstract_font)
{
}
#define INVALID_GLYPH 0x00
static inline CGGlyph
_cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
if (index > 0xffff)
return INVALID_GLYPH;
return (CGGlyph) index;
}
static inline cairo_status_t
_cairo_matrix_to_unit_quartz_matrix (const cairo_matrix_t *m, CGAffineTransform *txout,
double *xout, double *yout)
{
CGAffineTransform transform;
double xscale, yscale;
cairo_status_t status;
status = _cairo_matrix_compute_basis_scale_factors (m, &xscale, &yscale, 1);
if (status)
return status;
transform = CGAffineTransformMake (m->xx, - m->yx,
- m->xy, m->yy,
0.0f, 0.0f);
if (xout)
*xout = xscale;
if (yout)
*yout = yscale;
if (xscale)
xscale = 1.0 / xscale;
if (yscale)
yscale = 1.0 / yscale;
*txout = CGAffineTransformScale (transform, xscale, yscale);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
CGAffineTransform textMatrix;
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
int advance;
CGRect bbox;
double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
double xscale, yscale;
double xmin, ymin, xmax, ymax;
if (glyph == INVALID_GLYPH)
goto FAIL;
if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
!CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
goto FAIL;
status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale,
&xscale, &yscale, 1);
if (status)
goto FAIL;
bbox = CGRectMake (bbox.origin.x / emscale,
bbox.origin.y / emscale,
bbox.size.width / emscale,
bbox.size.height / emscale);
/* Should we want to always integer-align glyph extents, we can do so in this way */
#if 0
{
CGAffineTransform textMatrix;
textMatrix = CGAffineTransformMake (font->base.scale.xx,
-font->base.scale.yx,
-font->base.scale.xy,
font->base.scale.yy,
0.0f, 0.0f);
bbox = CGRectApplyAffineTransform (bbox, textMatrix);
bbox = CGRectIntegral (bbox);
bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
}
#endif
#if 0
fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph,
bbox.origin.x / emscale, bbox.origin.y / emscale,
bbox.size.width / emscale, bbox.size.height / emscale);
#endif
xmin = CGRectGetMinX(bbox);
ymin = CGRectGetMinY(bbox);
xmax = CGRectGetMaxX(bbox);
ymax = CGRectGetMaxY(bbox);
extents.x_bearing = xmin;
extents.y_bearing = - ymax;
extents.width = xmax - xmin;
extents.height = ymax - ymin;
extents.x_advance = (double) advance / emscale;
extents.y_advance = 0.0;
#if 0
fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph,
extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance);
#endif
FAIL:
_cairo_scaled_glyph_set_metrics (scaled_glyph,
&font->base,
&extents);
return status;
}
static void
_cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
switch (el->type) {
case kCGPathElementMoveToPoint:
_cairo_path_fixed_move_to (path,
_cairo_fixed_from_double(el->points[0].x),
_cairo_fixed_from_double(el->points[0].y));
break;
case kCGPathElementAddLineToPoint:
_cairo_path_fixed_line_to (path,
_cairo_fixed_from_double(el->points[0].x),
_cairo_fixed_from_double(el->points[0].y));
break;
case kCGPathElementAddQuadCurveToPoint: {
cairo_fixed_t fx, fy;
double x, y;
if (!_cairo_path_fixed_get_current_point (path, &fx, &fy))
fx = fy = 0;
x = _cairo_fixed_to_double (fx);
y = _cairo_fixed_to_double (fy);
_cairo_path_fixed_curve_to (path,
_cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0),
_cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0),
_cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0),
_cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0),
_cairo_fixed_from_double(el->points[1].x),
_cairo_fixed_from_double(el->points[1].y));
}
break;
case kCGPathElementAddCurveToPoint:
_cairo_path_fixed_curve_to (path,
_cairo_fixed_from_double(el->points[0].x),
_cairo_fixed_from_double(el->points[0].y),
_cairo_fixed_from_double(el->points[1].x),
_cairo_fixed_from_double(el->points[1].y),
_cairo_fixed_from_double(el->points[2].x),
_cairo_fixed_from_double(el->points[2].y));
break;
case kCGPathElementCloseSubpath:
_cairo_path_fixed_close_path (path);
break;
}
}
static cairo_int_status_t
_cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
CGAffineTransform textMatrix;
CGPathRef glyphPath;
cairo_path_fixed_t *path;
if (glyph == INVALID_GLYPH) {
_cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
return CAIRO_STATUS_SUCCESS;
}
textMatrix = CGAffineTransformMake (font->base.scale.xx,
-font->base.scale.yx,
-font->base.scale.xy,
font->base.scale.yy,
font->base.scale.x0,
font->base.scale.y0);
textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0));
glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
if (!glyphPath)
return CAIRO_INT_STATUS_UNSUPPORTED;
path = _cairo_path_fixed_create ();
if (!path) {
CGPathRelease (glyphPath);
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
}
CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);
CGPathRelease (glyphPath);
_cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
cairo_image_surface_t *surface = NULL;
CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
int advance;
CGRect bbox;
double width, height;
double xscale, yscale;
double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
CGColorSpaceRef gray;
CGContextRef cgContext = NULL;
CGAffineTransform textMatrix;
CGRect glyphRect, glyphRectInt;
CGPoint glyphOrigin;
//fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
/* Create blank 2x2 image if we don't have this character.
* Maybe we should draw a better missing-glyph slug or something,
* but this is ok for now.
*/
if (glyph == INVALID_GLYPH) {
surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
status = cairo_surface_status ((cairo_surface_t *) surface);
if (status)
return status;
_cairo_scaled_glyph_set_surface (scaled_glyph,
&font->base,
surface);
return CAIRO_STATUS_SUCCESS;
}
if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
!CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale,
&xscale, &yscale, 1);
if (status)
return status;
textMatrix = CGAffineTransformMake (font->base.scale.xx,
-font->base.scale.yx,
-font->base.scale.xy,
font->base.scale.yy,
0.0f, 0.0f);
glyphRect = CGRectMake (bbox.origin.x / emscale,
bbox.origin.y / emscale,
bbox.size.width / emscale,
bbox.size.height / emscale);
glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
/* Round the rectangle outwards, so that we don't have to deal
* with non-integer-pixel origins or dimensions.
*/
glyphRectInt = CGRectIntegral (glyphRect);
#if 0
fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height);
#endif
glyphOrigin = glyphRectInt.origin;
//textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
width = glyphRectInt.size.width;
height = glyphRectInt.size.height;
//fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
if (surface->base.status)
return surface->base.status;
gray = CGColorSpaceCreateDeviceGray ();
cgContext = CGBitmapContextCreate (surface->data,
surface->width,
surface->height,
8,
surface->stride,
gray,
kCGImageAlphaNone);
CGColorSpaceRelease (gray);
CGContextSetFont (cgContext, font_face->cgFont);
CGContextSetFontSize (cgContext, 1.0);
CGContextSetTextMatrix (cgContext, textMatrix);
CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height));
if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE)
CGContextSetShouldAntialias (cgContext, false);
CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0);
CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
CGContextRelease (cgContext);
cairo_surface_set_device_offset (&surface->base,
- glyphOrigin.x,
height + glyphOrigin.y);
_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
return status;
}
static cairo_int_status_t
_cairo_quartz_font_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_glyph_info_t info)
{
cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);
if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
return status;
}
static unsigned long
_cairo_quartz_ucs4_to_index (void *abstract_font,
uint32_t ucs4)
{
cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
UniChar u = (UniChar) ucs4;
CGGlyph glyph;
CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
return glyph;
}
const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
CAIRO_FONT_TYPE_QUARTZ,
_cairo_quartz_font_get_implementation,
_cairo_quartz_font_create_toy,
_cairo_quartz_font_fini,
_cairo_quartz_font_scaled_glyph_init,
NULL, /* text_to_glyphs */
_cairo_quartz_ucs4_to_index,
NULL, /* show_glyphs */
NULL, /* load_truetype_table */
NULL, /* map_glyphs_to_unicode */
};
/*
* private methods that the quartz surface uses
*/
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
{
cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
return ffont->cgFont;
}
/*
* compat with old ATSUI backend
*/
/**
* cairo_quartz_font_face_create_for_atsu_font_id
* @font_id: an ATSUFontID for the font.
*
* Creates a new font for the Quartz font backend based on an
* #ATSUFontID. This font can then be used with
* cairo_set_font_face() or cairo_scaled_font_create().
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.6
**/
cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
ATSFontRef atsFont = FMGetATSFontRefFromFont (font_id);
CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
cairo_font_face_t *ff;
ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
CGFontRelease (cgFont);
return ff;
}
/* This is the old name for the above function, exported for compat purposes */
cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
cairo_font_face_t *
cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
}

View file

@ -0,0 +1,286 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright <EFBFBD> 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#include "cairoint.h"
#include "cairo-quartz-image.h"
#include "cairo-quartz-private.h"
#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
#define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
static void
DataProviderReleaseCallback (void *info, const void *data, size_t size)
{
cairo_surface_t *surface = (cairo_surface_t *) info;
cairo_surface_destroy (surface);
}
static cairo_surface_t *
_cairo_quartz_image_surface_create_similar (void *asurface,
cairo_content_t content,
int width,
int height)
{
cairo_surface_t *result;
cairo_surface_t *isurf = cairo_image_surface_create (_cairo_format_from_content (content),
width,
height);
if (cairo_surface_status(isurf))
return isurf;
result = cairo_quartz_image_surface_create (isurf);
cairo_surface_destroy (isurf);
return result;
}
static cairo_status_t
_cairo_quartz_image_surface_finish (void *asurface)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
/* the imageSurface will be destroyed by the data provider's release callback */
CGImageRelease (surface->image);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_quartz_image_surface_acquire_source_image (void *asurface,
cairo_image_surface_t **image_out,
void **image_extra)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*image_out = surface->imageSurface;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_quartz_image_surface_acquire_dest_image (void *asurface,
cairo_rectangle_int_t *interest_rect,
cairo_image_surface_t **image_out,
cairo_rectangle_int_t *image_rect,
void **image_extra)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*image_out = surface->imageSurface;
*image_rect = surface->extents;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_quartz_image_surface_get_extents (void *asurface,
cairo_rectangle_int_t *extents)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
*extents = surface->extents;
return CAIRO_STATUS_SUCCESS;
}
/* we assume some drawing happened to the image buffer; make sure it's
* represented in the CGImage on flush()
*/
static cairo_status_t
_cairo_quartz_image_surface_flush (void *asurface)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
CGImageRef oldImage = surface->image;
CGImageRef newImage = NULL;
/* To be released by the ReleaseCallback */
cairo_surface_reference ((cairo_surface_t*) surface->imageSurface);
newImage = _cairo_quartz_create_cgimage (surface->imageSurface->format,
surface->imageSurface->width,
surface->imageSurface->height,
surface->imageSurface->stride,
surface->imageSurface->data,
TRUE,
NULL,
DataProviderReleaseCallback,
surface->imageSurface);
surface->image = newImage;
CGImageRelease (oldImage);
return CAIRO_STATUS_SUCCESS;
}
static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
_cairo_quartz_image_surface_create_similar,
_cairo_quartz_image_surface_finish,
_cairo_quartz_image_surface_acquire_source_image,
NULL, /* release_source_image */
_cairo_quartz_image_surface_acquire_dest_image,
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
NULL, /* set_clip_region */
NULL, /* intersect_clip_path */
_cairo_quartz_image_surface_get_extents,
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
_cairo_quartz_image_surface_flush,
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
NULL, /* paint */
NULL, /* mask */
NULL, /* stroke */
NULL, /* fill */
NULL, /* surface_show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL /* fill_stroke */
};
/**
* cairo_quartz_image_surface_create
* @surface: a cairo image surface to wrap with a quartz image surface
*
* Creates a Quartz surface backed by a CGImageRef that references the
* given image surface. The resulting surface can be rendered quickly
* when used as a source when rendering to a #cairo_quartz_surface. If
* the data in the image surface is ever updated, cairo_surface_flush()
* must be called on the #cairo_quartz_image_surface to ensure that the
* CGImageRef refers to the updated data.
*
* Return value: the newly created surface.
*
* Since: 1.6
*/
cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *surface)
{
cairo_quartz_image_surface_t *qisurf;
CGImageRef image;
cairo_image_surface_t *image_surface;
int width, height, stride;
cairo_format_t format;
unsigned char *data;
if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
return SURFACE_ERROR_TYPE_MISMATCH;
image_surface = (cairo_image_surface_t*) surface;
width = image_surface->width;
height = image_surface->height;
stride = image_surface->stride;
format = image_surface->format;
data = image_surface->data;
if (!_cairo_quartz_verify_surface_size(width, height))
return SURFACE_ERROR_NO_MEMORY;
if (width == 0 || height == 0)
return SURFACE_ERROR_NO_MEMORY;
if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24)
return SURFACE_ERROR_INVALID_FORMAT;
qisurf = malloc(sizeof(cairo_quartz_image_surface_t));
if (qisurf == NULL)
return SURFACE_ERROR_NO_MEMORY;
memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
/* In case the create_cgimage fails, this ref will
* be released via the callback (which will be called in
* case of failure.)
*/
cairo_surface_reference (surface);
image = _cairo_quartz_create_cgimage (format,
width, height,
stride,
data,
TRUE,
NULL,
DataProviderReleaseCallback,
image_surface);
if (!image) {
free (qisurf);
return SURFACE_ERROR_NO_MEMORY;
}
_cairo_surface_init (&qisurf->base,
&cairo_quartz_image_surface_backend,
_cairo_content_from_format (format));
qisurf->extents.x = qisurf->extents.y = 0;
qisurf->extents.width = width;
qisurf->extents.height = height;
qisurf->image = image;
qisurf->imageSurface = image_surface;
return &qisurf->base;
}
cairo_surface_t *
cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
if (cairo_surface_get_type(asurface) != CAIRO_SURFACE_TYPE_QUARTZ_IMAGE)
return NULL;
return (cairo_surface_t*) surface->imageSurface;
}

View file

@ -0,0 +1,59 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2008 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QUARTZ_IMAGE_H
#define CAIRO_QUARTZ_IMAGE_H
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_IMAGE_SURFACE
#include <Carbon/Carbon.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *image_surface);
cairo_public cairo_surface_t *
cairo_quartz_image_surface_get_image (cairo_surface_t *surface);
CAIRO_END_DECLS
#else /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */
# error Cairo was not compiled with support for the quartz-image backend
#endif /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */
#endif /* CAIRO_QUARTZ_IMAGE_H */

View file

@ -0,0 +1,104 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Calum Robinson
* Copyright (C) 2006,2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Calum Robinson
*
* Contributor(s):
* Calum Robinson <calumr@mac.com>
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QUARTZ_PRIVATE_H
#define CAIRO_QUARTZ_PRIVATE_H
#include "cairoint.h"
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-quartz.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;
CGContextRef cgContext;
CGAffineTransform cgContextBaseCTM;
void *imageData;
cairo_surface_t *imageSurfaceEquiv;
cairo_rectangle_int_t extents;
/* These are stored while drawing operations are in place, set up
* by quartz_setup_source() and quartz_finish_source()
*/
CGAffineTransform sourceTransform;
CGImageRef sourceImage;
cairo_surface_t *sourceImageSurface;
CGRect sourceImageRect;
CGShadingRef sourceShading;
CGPatternRef sourcePattern;
CGInterpolationQuality oldInterpolationQuality;
} cairo_quartz_surface_t;
typedef struct cairo_quartz_image_surface {
cairo_surface_t base;
cairo_rectangle_int_t extents;
CGImageRef image;
cairo_image_surface_t *imageSurface;
} cairo_quartz_image_surface_t;
cairo_bool_t
_cairo_quartz_verify_surface_size(int width, int height);
CGImageRef
_cairo_quartz_create_cgimage (cairo_format_t format,
unsigned int width,
unsigned int height,
unsigned int stride,
void *data,
cairo_bool_t interpolate,
CGColorSpaceRef colorSpaceOverride,
CGDataProviderReleaseDataCallback releaseCallback,
void *releaseInfo);
CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
#else
# error Cairo was not compiled with support for the quartz backend
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
#endif /* CAIRO_QUARTZ_PRIVATE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006, 2007 Mozilla Corporation
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is Mozilla Corporation.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@mozilla.com>
*/
#ifndef CAIRO_QUARTZ_H
#define CAIRO_QUARTZ_H
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_SURFACE
#include <ApplicationServices/ApplicationServices.h>
CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_quartz_surface_create (cairo_format_t format,
unsigned int width,
unsigned int height);
cairo_public cairo_surface_t *
cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height);
cairo_public CGContextRef
cairo_quartz_surface_get_cg_context (cairo_surface_t *surface);
#if CAIRO_HAS_QUARTZ_FONT
/*
* Quartz font support
*/
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font);
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id);
#endif /* CAIRO_HAS_QUARTZ_FONT */
CAIRO_END_DECLS
#else
# error Cairo was not compiled with support for the quartz backend
#endif /* CAIRO_HAS_QUARTZ_SURFACE */
#endif /* CAIRO_QUARTZ_H */

Some files were not shown because too many files have changed in this diff Show more