Back to index

lightning-sunbird  0.9+nobinonly
gfxContext.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Oracle Corporation code.
00016  *
00017  * The Initial Developer of the Original Code is Oracle Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Stuart Parmenter <pavlov@pavlov.net>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifdef _MSC_VER
00039 #define _USE_MATH_DEFINES
00040 #endif
00041 #include <math.h>
00042 
00043 #include "gfxContext.h"
00044 
00045 #include "gfxColor.h"
00046 #include "gfxMatrix.h"
00047 #include "gfxASurface.h"
00048 #include "gfxPattern.h"
00049 
00050 
00051 THEBES_IMPL_REFCOUNTING(gfxContext)
00052 
00053 gfxContext::gfxContext(gfxASurface *surface) :
00054     mSurface(surface)
00055 {
00056     mCairo = cairo_create(surface->CairoSurface());
00057 }
00058 gfxContext::~gfxContext()
00059 {
00060     cairo_destroy(mCairo);
00061 }
00062 
00063 gfxASurface *gfxContext::CurrentSurface()
00064 {
00065     return mSurface;
00066 }
00067 
00068 void gfxContext::Save()
00069 {
00070     cairo_save(mCairo);
00071 }
00072 
00073 void gfxContext::Restore()
00074 {
00075     cairo_restore(mCairo);
00076 }
00077 
00078 // drawing
00079 void gfxContext::NewPath()
00080 {
00081     cairo_new_path(mCairo);
00082 }
00083 void gfxContext::ClosePath()
00084 {
00085     cairo_close_path(mCairo);
00086 }
00087 
00088 void gfxContext::Stroke()
00089 {
00090     cairo_stroke_preserve(mCairo);
00091 }
00092 void gfxContext::Fill()
00093 {
00094     cairo_fill_preserve(mCairo);
00095 }
00096 
00097 void gfxContext::MoveTo(gfxPoint pt)
00098 {
00099     cairo_move_to(mCairo, pt.x, pt.y);
00100 }
00101 void gfxContext::LineTo(gfxPoint pt)
00102 {
00103     cairo_line_to(mCairo, pt.x, pt.y);
00104 }
00105 
00106 void gfxContext::CurveTo(gfxPoint pt1, gfxPoint pt2, gfxPoint pt3)
00107 {
00108     cairo_curve_to(mCairo, pt1.x, pt1.y, pt2.x, pt2.y, pt3.x, pt3.y);
00109 }
00110 
00111 void gfxContext::Arc(gfxPoint center, gfxFloat radius,
00112                      gfxFloat angle1, gfxFloat angle2)
00113 {
00114     cairo_arc(mCairo, center.x, center.y, radius, angle1, angle2);
00115 }
00116 
00117 void gfxContext::Line(gfxPoint start, gfxPoint end)
00118 {
00119     MoveTo(start);
00120     LineTo(end);
00121 }
00122 
00123 void gfxContext::Rectangle(gfxRect rect, PRBool snapToPixels)
00124 {
00125     if (snapToPixels) {
00126         gfxPoint p1 = UserToDevice(rect.pos);
00127         gfxPoint p2 = UserToDevice(rect.pos + rect.size);
00128 
00129         gfxPoint p3 = UserToDevice(rect.pos + gfxSize(rect.size.width, 0.0));
00130         gfxPoint p4 = UserToDevice(rect.pos + gfxSize(0.0, rect.size.height));
00131 
00132         if (p1.x != p4.x ||
00133             p2.x != p3.x ||
00134             p1.y != p3.y ||
00135             p2.y != p4.y)
00136             // rectangle is no longer axis-aligned after transforming, so don't snap
00137             goto dontsnap;
00138 
00139         cairo_matrix_t mat;
00140         cairo_get_matrix(mCairo, &mat);
00141 
00142         if (mat.xx != 1.0 ||
00143             mat.yy != 1.0)
00144             // if we're not at 1.0 scale, don't snap
00145             goto dontsnap;
00146 
00147         p1.round();
00148         p2.round();
00149 
00150         cairo_identity_matrix(mCairo);
00151         cairo_rectangle(mCairo, p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
00152         cairo_set_matrix(mCairo, &mat);
00153         return;
00154     }
00155 
00156 dontsnap:
00157     cairo_rectangle(mCairo, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
00158 }
00159 
00160 void gfxContext::Ellipse(gfxPoint center, gfxSize dimensions)
00161 {
00162     // circle?
00163     if (dimensions.width == dimensions.height) {
00164         double radius = dimensions.width / 2.0;
00165 
00166         cairo_arc(mCairo, center.x, center.y, radius, 0, 2.0 * M_PI);
00167     } else {
00168         double x = center.x;
00169         double y = center.y;
00170         double w = dimensions.width;
00171         double h = dimensions.height;
00172 
00173         cairo_new_path(mCairo);
00174         cairo_move_to(mCairo, x + w/2.0, y);
00175 
00176         cairo_rel_curve_to(mCairo,
00177                            0, 0,
00178                            w / 2.0, 0,
00179                            w / 2.0, h / 2.0);
00180         cairo_rel_curve_to(mCairo,
00181                            0, 0,
00182                            0, h / 2.0,
00183                            - w / 2.0, h / 2.0);
00184         cairo_rel_curve_to(mCairo,
00185                            0, 0,
00186                            - w / 2.0, 0,
00187                            - w / 2.0, - h / 2.0);
00188         cairo_rel_curve_to(mCairo,
00189                            0, 0,
00190                            0, - h / 2.0,
00191                            w / 2.0, - h / 2.0);
00192     }
00193 }
00194 
00195 void gfxContext::Polygon(const gfxPoint *points, PRUint32 numPoints)
00196 {
00197     if (numPoints == 0)
00198         return;
00199 
00200     cairo_move_to(mCairo, points[0].x, points[0].y);
00201     for (PRUint32 i = 1; i < numPoints; ++i) {
00202         cairo_line_to(mCairo, points[i].x, points[i].y);
00203     }
00204 }
00205 
00206 void gfxContext::DrawSurface(gfxASurface *surface, gfxSize size)
00207 {
00208     cairo_save(mCairo);
00209     cairo_set_source_surface(mCairo, surface->CairoSurface(), 0, 0);
00210     cairo_new_path(mCairo);
00211 
00212     // pixel-snap this
00213     Rectangle(gfxRect(gfxPoint(0.0, 0.0), size), PR_TRUE);
00214 
00215     cairo_fill(mCairo);
00216     cairo_restore(mCairo);
00217 }
00218 
00219 // transform stuff
00220 void gfxContext::Translate(gfxPoint pt)
00221 {
00222     cairo_translate(mCairo, pt.x, pt.y);
00223 }
00224 void gfxContext::Scale(gfxFloat x, gfxFloat y)
00225 {
00226     cairo_scale(mCairo, x, y);
00227 }
00228 void gfxContext::Rotate(gfxFloat angle)
00229 {
00230     cairo_rotate(mCairo, angle);
00231 }
00232 void gfxContext::Multiply(const gfxMatrix& matrix)
00233 {
00234     cairo_matrix_t mat = matrix.ToCairoMatrix();
00235     cairo_transform(mCairo, &mat);
00236 }
00237 
00238 void gfxContext::SetMatrix(const gfxMatrix& matrix)
00239 {
00240     cairo_matrix_t mat = matrix.ToCairoMatrix();
00241     cairo_set_matrix(mCairo, &mat);
00242 }
00243 
00244 void gfxContext::IdentityMatrix()
00245 {
00246     cairo_identity_matrix(mCairo);
00247 }
00248 
00249 gfxMatrix gfxContext::CurrentMatrix() const
00250 {
00251     cairo_matrix_t mat;
00252     cairo_get_matrix(mCairo, &mat);
00253     return gfxMatrix(mat);
00254 }
00255 
00256 gfxPoint gfxContext::DeviceToUser(gfxPoint point) const
00257 {
00258     gfxPoint ret = point;
00259     cairo_device_to_user(mCairo, &ret.x, &ret.y);
00260     return ret;
00261 }
00262 
00263 gfxSize gfxContext::DeviceToUser(gfxSize size) const
00264 {
00265     gfxSize ret = size;
00266     cairo_device_to_user_distance(mCairo, &ret.width, &ret.height);
00267     return ret;
00268 }
00269 
00270 gfxRect gfxContext::DeviceToUser(gfxRect rect) const
00271 {
00272     gfxRect ret = rect;
00273     cairo_device_to_user(mCairo, &ret.pos.x, &ret.pos.y);
00274     cairo_device_to_user_distance(mCairo, &ret.size.width, &ret.size.height);
00275     return ret;
00276 }
00277 
00278 gfxPoint gfxContext::UserToDevice(gfxPoint point) const
00279 {
00280     gfxPoint ret = point;
00281     cairo_user_to_device(mCairo, &ret.x, &ret.y);
00282     return ret;
00283 }
00284 
00285 gfxSize gfxContext::UserToDevice(gfxSize size) const
00286 {
00287     gfxSize ret = size;
00288     cairo_user_to_device_distance(mCairo, &ret.width, &ret.height);
00289     return ret;
00290 }
00291 
00292 gfxRect gfxContext::UserToDevice(gfxRect rect) const
00293 {
00294     gfxRect ret = rect;
00295     cairo_user_to_device(mCairo, &ret.pos.x, &ret.pos.y);
00296     cairo_user_to_device_distance(mCairo, &ret.size.width, &ret.size.height);
00297     return ret;
00298 }
00299 
00300 void gfxContext::SetAntialiasMode(AntialiasMode mode)
00301 {
00302     // XXX implement me
00303 }
00304 
00305 gfxContext::AntialiasMode gfxContext::CurrentAntialiasMode()
00306 {
00307     return MODE_COVERAGE;
00308 }
00309 
00310 void gfxContext::SetDash(gfxLineType ltype)
00311 {
00312     static double dash[] = {5.0, 5.0};
00313     static double dot[] = {1.0, 1.0};
00314 
00315     switch (ltype) {
00316         case gfxLineDashed:
00317             SetDash(dash, 2, 0.0);
00318             break;
00319         case gfxLineDotted:
00320             SetDash(dot, 2, 0.0);
00321             break;
00322         case gfxLineSolid:
00323         default:
00324             SetDash(nsnull, 0, 0.0);
00325             break;
00326     }
00327 }
00328 
00329 void gfxContext::SetDash(gfxFloat *dashes, int ndash, gfxFloat offset)
00330 {
00331     cairo_set_dash(mCairo, dashes, ndash, offset);
00332 }
00333 //void getDash() const;
00334 
00335 void gfxContext::SetLineWidth(gfxFloat width)
00336 {
00337     cairo_set_line_width(mCairo, width);
00338 }
00339 gfxFloat gfxContext::CurrentLineWidth() const
00340 {
00341     return cairo_get_line_width(mCairo);
00342 }
00343 
00344 void gfxContext::SetOperator(GraphicsOperator op)
00345 {
00346     cairo_set_operator(mCairo, (cairo_operator_t)op);
00347 }
00348 gfxContext::GraphicsOperator gfxContext::CurrentOperator() const
00349 {
00350     return (GraphicsOperator)cairo_get_operator(mCairo);
00351 }
00352 
00353 void gfxContext::SetLineCap(GraphicsLineCap cap)
00354 {
00355     cairo_set_line_cap(mCairo, (cairo_line_cap_t)cap);
00356 }
00357 gfxContext::GraphicsLineCap gfxContext::CurrentLineCap() const
00358 {
00359     return (GraphicsLineCap)cairo_get_line_cap(mCairo);
00360 }
00361 
00362 void gfxContext::SetLineJoin(GraphicsLineJoin join)
00363 {
00364     cairo_set_line_join(mCairo, (cairo_line_join_t)join);
00365 }
00366 gfxContext::GraphicsLineJoin gfxContext::CurrentLineJoin() const
00367 {
00368     return (GraphicsLineJoin)cairo_get_line_join(mCairo);
00369 }
00370 
00371 
00372 void gfxContext::SetMiterLimit(gfxFloat limit)
00373 {
00374     cairo_set_miter_limit(mCairo, limit);
00375 }
00376 gfxFloat gfxContext::CurrentMiterLimit() const
00377 {
00378     return cairo_get_miter_limit(mCairo);
00379 }
00380 
00381 
00382 // clipping
00383 void gfxContext::Clip(gfxRect rect)
00384 {
00385     cairo_new_path(mCairo);
00386     cairo_rectangle(mCairo, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
00387     cairo_clip(mCairo);
00388 }
00389 void gfxContext::Clip(const gfxRegion& region)
00390 {
00391 }
00392 
00393 void gfxContext::Clip()
00394 {
00395     cairo_clip_preserve(mCairo);
00396 }
00397 
00398 void gfxContext::ResetClip()
00399 {
00400     cairo_reset_clip(mCairo);
00401 }
00402 
00403 
00404 // rendering sources
00405 
00406 void gfxContext::SetColor(const gfxRGBA& c)
00407 {
00408     cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a);
00409 }
00410 
00411 void gfxContext::SetPattern(gfxPattern *pattern)
00412 {
00413     cairo_set_source(mCairo, pattern->CairoPattern());
00414 }
00415 
00416 void gfxContext::SetSource(gfxASurface *surface, gfxPoint offset)
00417 {
00418     cairo_set_source_surface(mCairo, surface->CairoSurface(), offset.x, offset.y);
00419 }
00420 
00421 // fonts?
00422 void gfxContext::DrawString(gfxTextRun& text, int pos, int len)
00423 {
00424 
00425 }
00426 
00427 void gfxContext::Paint(gfxFloat alpha)
00428 {
00429     cairo_paint_with_alpha(mCairo, alpha);
00430 }
00431 
00432 // filters
00433 void gfxContext::PushFilter(gfxFilter& filter, FilterHints hints, gfxRect& maxArea)
00434 {
00435 
00436 }
00437 
00438 void gfxContext::PopFilter()
00439 {
00440 
00441 }