Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / gfx / src / thebes / nsThebesRenderingContext.cpp
blob6e99e81018d8bc3363008d90b818fab5a0a994a3
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * mozilla.org.
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Stuart Parmenter <pavlov@pavlov.net>
24 * Vladimir Vukicevic <vladimir@pobox.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsThebesRenderingContext.h"
41 #include "nsThebesDeviceContext.h"
43 #include "nsRect.h"
44 #include "nsString.h"
45 #include "nsTransform2D.h"
46 #include "nsIRegion.h"
47 #include "nsIServiceManager.h"
48 #include "nsIInterfaceRequestorUtils.h"
49 #include "nsGfxCIID.h"
51 #include "imgIContainer.h"
52 #include "gfxIImageFrame.h"
53 #include "nsIImage.h"
55 #include "nsIThebesFontMetrics.h"
56 #include "nsThebesRegion.h"
57 #include "nsThebesImage.h"
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <fcntl.h>
63 #include "gfxPlatform.h"
65 #ifdef XP_WIN
66 #include "gfxWindowsSurface.h"
67 #include "cairo-win32.h"
68 #endif
70 static NS_DEFINE_CID(kRegionCID, NS_REGION_CID);
72 //////////////////////////////////////////////////////////////////////
74 // XXXTodo: rename FORM_TWIPS to FROM_APPUNITS
75 #define FROM_TWIPS(_x) ((gfxFloat)((_x)/(mP2A)))
76 #define FROM_TWIPS_INT(_x) (NSToIntRound((gfxFloat)((_x)/(mP2A))))
77 #define TO_TWIPS(_x) ((nscoord)((_x)*(mP2A)))
78 #define GFX_RECT_FROM_TWIPS_RECT(_r) (gfxRect(FROM_TWIPS((_r).x), FROM_TWIPS((_r).y), FROM_TWIPS((_r).width), FROM_TWIPS((_r).height)))
80 //////////////////////////////////////////////////////////////////////
82 NS_IMPL_ISUPPORTS1(nsThebesRenderingContext, nsIRenderingContext)
84 nsThebesRenderingContext::nsThebesRenderingContext() :
85 mLineStyle(nsLineStyle_kNone)
89 nsThebesRenderingContext::~nsThebesRenderingContext()
93 //////////////////////////////////////////////////////////////////////
94 //// nsIRenderingContext
96 NS_IMETHODIMP
97 nsThebesRenderingContext::Init(nsIDeviceContext* aContext, gfxASurface *aThebesSurface)
99 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Init ctx %p thebesSurface %p\n", this, aContext, aThebesSurface));
101 mDeviceContext = aContext;
102 mWidget = nsnull;
104 mThebes = new gfxContext(aThebesSurface);
106 return (CommonInit());
109 NS_IMETHODIMP
110 nsThebesRenderingContext::Init(nsIDeviceContext* aContext, gfxContext *aThebesContext)
112 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Init ctx %p thebesContext %p\n", this, aContext, aThebesContext));
114 mDeviceContext = aContext;
115 mWidget = nsnull;
117 mThebes = aThebesContext;
119 return (CommonInit());
122 NS_IMETHODIMP
123 nsThebesRenderingContext::Init(nsIDeviceContext* aContext, nsIWidget *aWidget)
125 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Init ctx %p widget %p\n", this, aContext, aWidget));
127 mDeviceContext = aContext;
128 mWidget = aWidget;
130 mThebes = new gfxContext(aWidget->GetThebesSurface());
132 //mThebes->SetColor(gfxRGBA(0.9, 0.0, 0.0, 0.3));
133 //mThebes->Paint();
135 //mThebes->Translate(gfxPoint(300,0));
136 //mThebes->Rotate(M_PI/4);
138 return (CommonInit());
141 NS_IMETHODIMP
142 nsThebesRenderingContext::CommonInit(void)
144 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::CommonInit\n", this));
146 mThebes->SetLineWidth(1.0);
148 mP2A = mDeviceContext->AppUnitsPerDevPixel();
150 return NS_OK;
153 NS_IMETHODIMP
154 nsThebesRenderingContext::GetDeviceContext(nsIDeviceContext *& aDeviceContext)
156 aDeviceContext = mDeviceContext;
157 NS_IF_ADDREF(aDeviceContext);
158 return NS_OK;
161 NS_IMETHODIMP
162 nsThebesRenderingContext::PushTranslation(PushedTranslation* aState)
164 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PushTranslation\n", this));
166 // XXX this is slow!
167 PushState();
168 return NS_OK;
171 NS_IMETHODIMP
172 nsThebesRenderingContext::PopTranslation(PushedTranslation* aState)
174 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PopTranslation\n", this));
176 // XXX this is slow!
177 PopState();
178 return NS_OK;
181 NS_IMETHODIMP
182 nsThebesRenderingContext::SetTranslation(nscoord aX, nscoord aY)
184 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetTranslation %d %d\n", this, aX, aY));
186 gfxMatrix newMat(mThebes->CurrentMatrix());
187 newMat.x0 = aX;
188 newMat.y0 = aY;
189 mThebes->SetMatrix(newMat);
190 return NS_OK;
193 NS_IMETHODIMP
194 nsThebesRenderingContext::PushState()
196 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PushState\n", this));
198 mThebes->Save();
199 return NS_OK;
202 NS_IMETHODIMP
203 nsThebesRenderingContext::PopState()
205 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PopState\n", this));
207 mThebes->Restore();
208 return NS_OK;
212 // clipping
215 NS_IMETHODIMP
216 nsThebesRenderingContext::SetClipRect(const nsRect& aRect,
217 nsClipCombine aCombine)
219 //return NS_OK;
220 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetClipRect [%d,%d,%d,%d] %d\n", this, aRect.x, aRect.y, aRect.width, aRect.height, aCombine));
222 if (aCombine == nsClipCombine_kReplace) {
223 mThebes->ResetClip();
224 } else if (aCombine != nsClipCombine_kIntersect) {
225 NS_WARNING("Unexpected usage of SetClipRect");
228 mThebes->NewPath();
229 gfxRect clipRect(GFX_RECT_FROM_TWIPS_RECT(aRect));
230 if (mThebes->UserToDevicePixelSnapped(clipRect, PR_TRUE)) {
231 gfxMatrix mat(mThebes->CurrentMatrix());
232 mThebes->IdentityMatrix();
233 mThebes->Rectangle(clipRect);
234 mThebes->SetMatrix(mat);
235 } else {
236 mThebes->Rectangle(clipRect);
239 mThebes->Clip();
241 return NS_OK;
244 NS_IMETHODIMP
245 nsThebesRenderingContext::SetClipRegion(const nsIRegion& pxRegion,
246 nsClipCombine aCombine)
248 //return NS_OK;
249 // Region is in device coords, no transformation.
250 // This should only be called when there is no transform in place, when we
251 // we just start painting a widget. The region is set by the platform paint
252 // routine.
253 NS_ASSERTION(aCombine == nsClipCombine_kReplace,
254 "Unexpected usage of SetClipRegion");
256 nsRegionComplexity cplx;
257 pxRegion.GetRegionComplexity(cplx);
259 gfxMatrix mat = mThebes->CurrentMatrix();
260 mThebes->IdentityMatrix();
262 mThebes->ResetClip();
263 // GetBoundingBox, GetRects, FreeRects are non-const
264 nsIRegion *evilPxRegion = const_cast<nsIRegion*>(&pxRegion);
265 if (cplx == eRegionComplexity_rect) {
266 PRInt32 x, y, w, h;
267 evilPxRegion->GetBoundingBox(&x, &y, &w, &h);
269 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetClipRegion %d [%d,%d,%d,%d]", this, cplx, x, y, w, h));
271 mThebes->NewPath();
272 mThebes->Rectangle(gfxRect(x, y, w, h), PR_TRUE);
273 mThebes->Clip();
274 } else if (cplx == eRegionComplexity_complex) {
275 nsRegionRectSet *rects = nsnull;
276 nsresult rv = evilPxRegion->GetRects (&rects);
277 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetClipRegion %d %d rects", this, cplx, rects->mNumRects));
278 if (NS_FAILED(rv) || !rects) {
279 mThebes->SetMatrix(mat);
280 return rv;
283 mThebes->NewPath();
284 for (PRUint32 i = 0; i < rects->mNumRects; i++) {
285 mThebes->Rectangle(gfxRect(rects->mRects[i].x,
286 rects->mRects[i].y,
287 rects->mRects[i].width,
288 rects->mRects[i].height),
289 PR_TRUE);
291 mThebes->Clip();
293 evilPxRegion->FreeRects (rects);
296 mThebes->SetMatrix(mat);
298 return NS_OK;
301 // other junk
304 NS_IMETHODIMP
305 nsThebesRenderingContext::SetLineStyle(nsLineStyle aLineStyle)
307 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetLineStyle %d\n", this, aLineStyle));
308 switch (aLineStyle) {
309 case nsLineStyle_kSolid:
310 mThebes->SetDash(gfxContext::gfxLineSolid);
311 break;
312 case nsLineStyle_kDashed:
313 mThebes->SetDash(gfxContext::gfxLineDashed);
314 break;
315 case nsLineStyle_kDotted:
316 mThebes->SetDash(gfxContext::gfxLineDotted);
317 break;
318 case nsLineStyle_kNone:
319 default:
320 // nothing uses kNone
321 NS_ERROR("SetLineStyle: Invalid line style");
322 break;
325 mLineStyle = aLineStyle;
326 return NS_OK;
330 NS_IMETHODIMP
331 nsThebesRenderingContext::SetColor(nscolor aColor)
333 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetColor 0x%08x\n", this, aColor));
334 /* This sets the color assuming the sRGB color space, since that's what all
335 * CSS colors are defined to be in by the spec.
337 mThebes->SetColor(gfxRGBA(aColor));
339 mColor = aColor;
340 return NS_OK;
343 NS_IMETHODIMP
344 nsThebesRenderingContext::GetColor(nscolor &aColor) const
346 aColor = mColor;
347 return NS_OK;
350 NS_IMETHODIMP
351 nsThebesRenderingContext::Translate(nscoord aX, nscoord aY)
353 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Translate %d %d\n", this, aX, aY));
354 mThebes->Translate (gfxPoint(FROM_TWIPS(aX), FROM_TWIPS(aY)));
355 return NS_OK;
358 NS_IMETHODIMP
359 nsThebesRenderingContext::Scale(float aSx, float aSy)
361 // as far as I can tell, noone actually calls this
362 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::Scale %f %f\n", this, aSx, aSy));
363 mThebes->Scale (aSx, aSy);
364 return NS_OK;
367 void
368 nsThebesRenderingContext::UpdateTempTransformMatrix()
370 //PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::UpdateTempTransformMatrix\n", this));
372 /*****
373 * Thebes matrix layout: gfx matrix layout:
374 * | xx yx 0 | | m00 m01 0 |
375 * | xy yy 0 | | m10 m11 0 |
376 * | x0 y0 1 | | m20 m21 1 |
377 *****/
379 const gfxMatrix& ctm = mThebes->CurrentMatrix();
380 NS_ASSERTION(ctm.yx == 0 && ctm.xy == 0, "Can't represent Thebes matrix to Gfx");
381 mTempTransform.SetToTranslate(TO_TWIPS(ctm.x0), TO_TWIPS(ctm.y0));
382 mTempTransform.AddScale(ctm.xx, ctm.yy);
385 nsTransform2D&
386 nsThebesRenderingContext::CurrentTransform()
388 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::CurrentTransform\n", this));
389 UpdateTempTransformMatrix();
390 return mTempTransform;
393 /****
394 **** XXXXXX
395 ****
396 **** On other gfx implementations, the transform returned by this
397 **** has a built in twips to pixels ratio. That is, you pass in
398 **** twips to any nsTransform2D TransformCoord method, and you
399 **** get back pixels. This makes no sense. We don't do this.
400 **** This in turn breaks SVG and <object>; those should just be
401 **** fixed to not use this!
402 ****/
404 NS_IMETHODIMP
405 nsThebesRenderingContext::GetCurrentTransform(nsTransform2D *&aTransform)
407 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::GetCurrentTransform\n", this));
408 UpdateTempTransformMatrix();
409 aTransform = &mTempTransform;
410 return NS_OK;
413 void
414 nsThebesRenderingContext::TransformCoord (nscoord *aX, nscoord *aY)
416 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::TransformCoord\n", this));
418 gfxPoint pt(FROM_TWIPS(*aX), FROM_TWIPS(*aY));
420 pt = mThebes->UserToDevice (pt);
422 *aX = TO_TWIPS(pt.x);
423 *aY = TO_TWIPS(pt.y);
426 NS_IMETHODIMP
427 nsThebesRenderingContext::DrawLine(nscoord aX0, nscoord aY0, nscoord aX1, nscoord aY1)
429 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::DrawLine %d %d %d %d\n", this, aX0, aY0, aX1, aY1));
431 gfxPoint p0 = gfxPoint(FROM_TWIPS(aX0), FROM_TWIPS(aY0));
432 gfxPoint p1 = gfxPoint(FROM_TWIPS(aX1), FROM_TWIPS(aY1));
434 // we can't draw thick lines with gfx, so we always assume we want pixel-aligned
435 // lines if the rendering context is at 1.0 scale
436 gfxMatrix savedMatrix = mThebes->CurrentMatrix();
437 if (!savedMatrix.HasNonTranslation()) {
438 p0 = mThebes->UserToDevice(p0);
439 p1 = mThebes->UserToDevice(p1);
441 p0.Round();
442 p1.Round();
444 mThebes->IdentityMatrix();
446 mThebes->NewPath();
448 // snap straight lines
449 if (p0.x == p1.x) {
450 mThebes->Line(p0 + gfxPoint(0.5, 0),
451 p1 + gfxPoint(0.5, 0));
452 } else if (p0.y == p1.y) {
453 mThebes->Line(p0 + gfxPoint(0, 0.5),
454 p1 + gfxPoint(0, 0.5));
455 } else {
456 mThebes->Line(p0, p1);
459 mThebes->Stroke();
461 mThebes->SetMatrix(savedMatrix);
462 } else {
463 mThebes->NewPath();
464 mThebes->Line(p0, p1);
465 mThebes->Stroke();
468 return NS_OK;
471 NS_IMETHODIMP
472 nsThebesRenderingContext::DrawRect(const nsRect& aRect)
474 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::DrawRect [%d,%d,%d,%d]\n", this, aRect.x, aRect.y, aRect.width, aRect.height));
476 mThebes->NewPath();
477 mThebes->Rectangle(GFX_RECT_FROM_TWIPS_RECT(aRect), PR_TRUE);
478 mThebes->Stroke();
480 return NS_OK;
483 NS_IMETHODIMP
484 nsThebesRenderingContext::DrawRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
486 DrawRect(nsRect(aX, aY, aWidth, aHeight));
487 return NS_OK;
491 /* Clamp r to (0,0) (2^23,2^23)
492 * these are to be device coordinates.
494 * Returns PR_FALSE if the rectangle is completely out of bounds,
495 * PR_TRUE otherwise.
497 * This function assumes that it will be called with a rectangle being
498 * drawn into a surface with an identity transformation matrix; that
499 * is, anything above or to the left of (0,0) will be offscreen.
501 * First it checks if the rectangle is entirely beyond
502 * CAIRO_COORD_MAX; if so, it can't ever appear on the screen --
503 * PR_FALSE is returned.
505 * Then it shifts any rectangles with x/y < 0 so that x and y are = 0,
506 * and adjusts the width and height appropriately. For example, a
507 * rectangle from (0,-5) with dimensions (5,10) will become a
508 * rectangle from (0,0) with dimensions (5,5).
510 * If after negative x/y adjustment to 0, either the width or height
511 * is negative, then the rectangle is completely offscreen, and
512 * nothing is drawn -- PR_FALSE is returned.
514 * Finally, if x+width or y+height are greater than CAIRO_COORD_MAX,
515 * the width and height are clamped such x+width or y+height are equal
516 * to CAIRO_COORD_MAX, and PR_TRUE is returned.
518 #define CAIRO_COORD_MAX (8388608.0)
520 static PRBool
521 ConditionRect(gfxRect& r) {
522 // if either x or y is way out of bounds;
523 // note that we don't handle negative w/h here
524 if (r.pos.x > CAIRO_COORD_MAX || r.pos.y > CAIRO_COORD_MAX)
525 return PR_FALSE;
527 if (r.pos.x < 0.0) {
528 r.size.width += r.pos.x;
529 if (r.size.width < 0.0)
530 return PR_FALSE;
531 r.pos.x = 0.0;
534 if (r.pos.x + r.size.width > CAIRO_COORD_MAX) {
535 r.size.width = CAIRO_COORD_MAX - r.pos.x;
538 if (r.pos.y < 0.0) {
539 r.size.height += r.pos.y;
540 if (r.size.height < 0.0)
541 return PR_FALSE;
543 r.pos.y = 0.0;
546 if (r.pos.y + r.size.height > CAIRO_COORD_MAX) {
547 r.size.height = CAIRO_COORD_MAX - r.pos.y;
549 return PR_TRUE;
552 NS_IMETHODIMP
553 nsThebesRenderingContext::FillRect(const nsRect& aRect)
555 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillRect [%d,%d,%d,%d]\n", this, aRect.x, aRect.y, aRect.width, aRect.height));
557 gfxRect r(GFX_RECT_FROM_TWIPS_RECT(aRect));
559 /* Clamp coordinates to work around a design bug in cairo */
560 nscoord bigval = (nscoord)(CAIRO_COORD_MAX*mP2A);
561 if (aRect.width > bigval ||
562 aRect.height > bigval ||
563 aRect.x < -bigval ||
564 aRect.x > bigval ||
565 aRect.y < -bigval ||
566 aRect.y > bigval)
568 gfxMatrix mat = mThebes->CurrentMatrix();
570 r = mat.Transform(r);
572 if (!ConditionRect(r))
573 return NS_OK;
575 mThebes->IdentityMatrix();
576 mThebes->NewPath();
578 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillRect conditioned to [%f,%f,%f,%f]\n", this, r.pos.x, r.pos.y, r.size.width, r.size.height));
580 mThebes->Rectangle(r, PR_TRUE);
581 mThebes->Fill();
582 mThebes->SetMatrix(mat);
584 return NS_OK;
587 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillRect raw [%f,%f,%f,%f]\n", this, r.pos.x, r.pos.y, r.size.width, r.size.height));
589 mThebes->NewPath();
590 mThebes->Rectangle(r, PR_TRUE);
591 mThebes->Fill();
593 return NS_OK;
596 NS_IMETHODIMP
597 nsThebesRenderingContext::FillRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
599 FillRect(nsRect(aX, aY, aWidth, aHeight));
600 return NS_OK;
603 NS_IMETHODIMP
604 nsThebesRenderingContext::InvertRect(const nsRect& aRect)
606 gfxContext::GraphicsOperator lastOp = mThebes->CurrentOperator();
608 mThebes->SetOperator(gfxContext::OPERATOR_XOR);
609 nsresult rv = FillRect(aRect);
610 mThebes->SetOperator(lastOp);
612 return rv;
615 NS_IMETHODIMP
616 nsThebesRenderingContext::InvertRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
618 return InvertRect(nsRect(aX, aY, aWidth, aHeight));
621 NS_IMETHODIMP
622 nsThebesRenderingContext::DrawEllipse(const nsRect& aRect)
624 return DrawEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
627 NS_IMETHODIMP
628 nsThebesRenderingContext::DrawEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
630 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::DrawEllipse [%d,%d,%d,%d]\n", this, aX, aY, aWidth, aHeight));
632 mThebes->NewPath();
633 mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0,
634 FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0),
635 gfxSize(FROM_TWIPS(aWidth),
636 FROM_TWIPS(aHeight)));
637 mThebes->Stroke();
639 return NS_OK;
642 NS_IMETHODIMP
643 nsThebesRenderingContext::FillEllipse(const nsRect& aRect)
645 return FillEllipse(aRect.x, aRect.y, aRect.width, aRect.height);
648 NS_IMETHODIMP
649 nsThebesRenderingContext::FillEllipse(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight)
651 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillEllipse [%d,%d,%d,%d]\n", this, aX, aY, aWidth, aHeight));
653 mThebes->NewPath();
654 mThebes->Ellipse(gfxPoint(FROM_TWIPS(aX) + FROM_TWIPS(aWidth)/2.0,
655 FROM_TWIPS(aY) + FROM_TWIPS(aHeight)/2.0),
656 gfxSize(FROM_TWIPS(aWidth),
657 FROM_TWIPS(aHeight)));
658 mThebes->Fill();
660 return NS_OK;
663 NS_IMETHODIMP
664 nsThebesRenderingContext::FillPolygon(const nsPoint twPoints[], PRInt32 aNumPoints)
666 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::FillPolygon %d\n", this, aNumPoints));
668 if (aNumPoints == 0)
669 return NS_OK;
671 if (aNumPoints == 4) {
674 nsAutoArrayPtr<gfxPoint> pxPoints(new gfxPoint[aNumPoints]);
676 for (int i = 0; i < aNumPoints; i++) {
677 pxPoints[i].x = FROM_TWIPS(twPoints[i].x);
678 pxPoints[i].y = FROM_TWIPS(twPoints[i].y);
681 mThebes->NewPath();
682 mThebes->Polygon(pxPoints, aNumPoints);
683 mThebes->Fill();
685 return NS_OK;
688 void*
689 nsThebesRenderingContext::GetNativeGraphicData(GraphicDataType aType)
691 if (aType == NATIVE_GDK_DRAWABLE)
693 if (mWidget)
694 return mWidget->GetNativeData(NS_NATIVE_WIDGET);
696 if (aType == NATIVE_THEBES_CONTEXT)
697 return mThebes;
698 if (aType == NATIVE_CAIRO_CONTEXT)
699 return mThebes->GetCairo();
700 #ifdef XP_WIN
701 if (aType == NATIVE_WINDOWS_DC) {
702 nsRefPtr<gfxASurface> surf(mThebes->CurrentSurface());
703 if (!surf || surf->CairoStatus())
704 return nsnull;
705 return static_cast<gfxWindowsSurface*>(static_cast<gfxASurface*>(surf.get()))->GetDC();
707 #endif
708 #ifdef XP_OS2
709 if (aType == NATIVE_OS2_PS) {
710 nsRefPtr<gfxASurface> surf(mThebes->CurrentSurface());
711 if (!surf || surf->CairoStatus())
712 return nsnull;
713 return (void*)(static_cast<gfxOS2Surface*>(static_cast<gfxASurface*>(surf.get()))->GetPS());
715 #endif
717 return nsnull;
720 NS_IMETHODIMP
721 nsThebesRenderingContext::PushFilter(const nsRect& twRect, PRBool aAreaIsOpaque, float aOpacity)
723 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG,
724 ("## %p nsTRC::PushFilter [%d,%d,%d,%d] isOpaque: %d opacity: %f\n",
725 this, twRect.x, twRect.y, twRect.width, twRect.height,
726 aAreaIsOpaque, aOpacity));
728 mOpacityArray.AppendElement(aOpacity);
730 mThebes->Save();
731 mThebes->Clip(GFX_RECT_FROM_TWIPS_RECT(twRect));
732 mThebes->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
734 return NS_OK;
737 NS_IMETHODIMP
738 nsThebesRenderingContext::PopFilter()
740 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::PopFilter\n"));
742 if (mOpacityArray.Length() > 0) {
743 float f = mOpacityArray[mOpacityArray.Length()-1];
744 mOpacityArray.RemoveElementAt(mOpacityArray.Length()-1);
746 mThebes->PopGroupToSource();
748 if (f < 0.0) {
749 mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
750 mThebes->Paint();
751 } else {
752 mThebes->SetOperator(gfxContext::OPERATOR_OVER);
753 mThebes->Paint(f);
756 mThebes->Restore();
760 return NS_OK;
764 // text junk
766 NS_IMETHODIMP
767 nsThebesRenderingContext::SetRightToLeftText(PRBool aIsRTL)
769 return mFontMetrics->SetRightToLeftText(aIsRTL);
772 NS_IMETHODIMP
773 nsThebesRenderingContext::GetRightToLeftText(PRBool* aIsRTL)
775 *aIsRTL = mFontMetrics->GetRightToLeftText();
776 return NS_OK;
779 void
780 nsThebesRenderingContext::SetTextRunRTL(PRBool aIsRTL)
782 mFontMetrics->SetTextRunRTL(aIsRTL);
785 NS_IMETHODIMP
786 nsThebesRenderingContext::SetFont(const nsFont& aFont, nsIAtom* aLangGroup,
787 gfxUserFontSet *aUserFontSet)
789 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetFont %p\n", this, &aFont));
791 nsCOMPtr<nsIFontMetrics> newMetrics;
792 mDeviceContext->GetMetricsFor(aFont, aLangGroup, aUserFontSet,
793 *getter_AddRefs(newMetrics));
794 mFontMetrics = reinterpret_cast<nsIThebesFontMetrics*>(newMetrics.get());
795 return NS_OK;
798 NS_IMETHODIMP
799 nsThebesRenderingContext::SetFont(nsIFontMetrics *aFontMetrics)
801 PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::SetFont[Metrics] %p\n", this, aFontMetrics));
803 mFontMetrics = static_cast<nsIThebesFontMetrics*>(aFontMetrics);
804 return NS_OK;
807 NS_IMETHODIMP
808 nsThebesRenderingContext::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
810 aFontMetrics = mFontMetrics;
811 NS_IF_ADDREF(aFontMetrics);
812 return NS_OK;
815 PRInt32
816 nsThebesRenderingContext::GetMaxStringLength()
818 if (!mFontMetrics)
819 return 1;
820 return mFontMetrics->GetMaxStringLength();
823 NS_IMETHODIMP
824 nsThebesRenderingContext::GetWidth(char aC, nscoord &aWidth)
826 if (aC == ' ' && mFontMetrics)
827 return mFontMetrics->GetSpaceWidth(aWidth);
829 return GetWidth(&aC, 1, aWidth);
832 NS_IMETHODIMP
833 nsThebesRenderingContext::GetWidth(PRUnichar aC, nscoord &aWidth, PRInt32 *aFontID)
835 return GetWidth(&aC, 1, aWidth, aFontID);
838 NS_IMETHODIMP
839 nsThebesRenderingContext::GetWidthInternal(const char* aString, PRUint32 aLength, nscoord& aWidth)
841 #ifdef DISABLE_TEXT
842 aWidth = (8 * aLength);
843 return NS_OK;
844 #endif
846 if (aLength == 0) {
847 aWidth = 0;
848 return NS_OK;
851 return mFontMetrics->GetWidth(aString, aLength, aWidth, this);
854 NS_IMETHODIMP
855 nsThebesRenderingContext::GetWidthInternal(const PRUnichar *aString, PRUint32 aLength,
856 nscoord &aWidth, PRInt32 *aFontID)
858 #ifdef DISABLE_TEXT
859 aWidth = (8 * aLength);
860 return NS_OK;
861 #endif
863 if (aLength == 0) {
864 aWidth = 0;
865 return NS_OK;
868 return mFontMetrics->GetWidth(aString, aLength, aWidth, aFontID, this);
871 NS_IMETHODIMP
872 nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString, PRUint32 aLength,
873 nsTextDimensions& aDimensions)
875 mFontMetrics->GetMaxAscent(aDimensions.ascent);
876 mFontMetrics->GetMaxDescent(aDimensions.descent);
877 return GetWidth(aString, aLength, aDimensions.width);
880 NS_IMETHODIMP
881 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
882 PRUint32 aLength,
883 nsTextDimensions& aDimensions,
884 PRInt32* aFontID)
886 mFontMetrics->GetMaxAscent(aDimensions.ascent);
887 mFontMetrics->GetMaxDescent(aDimensions.descent);
888 return GetWidth(aString, aLength, aDimensions.width, aFontID);
891 #if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) || defined(XP_MACOSX) || defined (MOZ_DFB)
892 NS_IMETHODIMP
893 nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString,
894 PRInt32 aLength,
895 PRInt32 aAvailWidth,
896 PRInt32* aBreaks,
897 PRInt32 aNumBreaks,
898 nsTextDimensions& aDimensions,
899 PRInt32& aNumCharsFit,
900 nsTextDimensions& aLastWordDimensions,
901 PRInt32* aFontID)
903 return NS_ERROR_NOT_IMPLEMENTED;
906 NS_IMETHODIMP
907 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
908 PRInt32 aLength,
909 PRInt32 aAvailWidth,
910 PRInt32* aBreaks,
911 PRInt32 aNumBreaks,
912 nsTextDimensions& aDimensions,
913 PRInt32& aNumCharsFit,
914 nsTextDimensions& aLastWordDimensions,
915 PRInt32* aFontID)
917 return NS_ERROR_NOT_IMPLEMENTED;
919 #endif
921 #ifdef MOZ_MATHML
922 NS_IMETHODIMP
923 nsThebesRenderingContext::GetBoundingMetricsInternal(const char* aString,
924 PRUint32 aLength,
925 nsBoundingMetrics& aBoundingMetrics)
927 return mFontMetrics->GetBoundingMetrics(aString, aLength, this, aBoundingMetrics);
930 NS_IMETHODIMP
931 nsThebesRenderingContext::GetBoundingMetricsInternal(const PRUnichar* aString,
932 PRUint32 aLength,
933 nsBoundingMetrics& aBoundingMetrics,
934 PRInt32* aFontID)
936 return mFontMetrics->GetBoundingMetrics(aString, aLength, this, aBoundingMetrics);
938 #endif // MOZ_MATHML
940 NS_IMETHODIMP
941 nsThebesRenderingContext::DrawStringInternal(const char *aString, PRUint32 aLength,
942 nscoord aX, nscoord aY,
943 const nscoord* aSpacing)
945 #ifdef DISABLE_TEXT
946 return NS_OK;
947 #endif
949 return mFontMetrics->DrawString(aString, aLength, aX, aY, aSpacing,
950 this);
953 NS_IMETHODIMP
954 nsThebesRenderingContext::DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
955 nscoord aX, nscoord aY,
956 PRInt32 aFontID,
957 const nscoord* aSpacing)
959 #ifdef DISABLE_TEXT
960 return NS_OK;
961 #endif
963 return mFontMetrics->DrawString(aString, aLength, aX, aY, aFontID,
964 aSpacing, this);
967 PRInt32
968 nsThebesRenderingContext::GetPosition(const PRUnichar *aText,
969 PRUint32 aLength,
970 nsPoint aPt)
972 return -1;
975 NS_IMETHODIMP
976 nsThebesRenderingContext::GetRangeWidth(const PRUnichar *aText,
977 PRUint32 aLength,
978 PRUint32 aStart,
979 PRUint32 aEnd,
980 PRUint32 &aWidth)
982 return NS_ERROR_NOT_IMPLEMENTED;
985 NS_IMETHODIMP
986 nsThebesRenderingContext::GetRangeWidth(const char *aText,
987 PRUint32 aLength,
988 PRUint32 aStart,
989 PRUint32 aEnd,
990 PRUint32 &aWidth)
992 return NS_ERROR_NOT_IMPLEMENTED;
995 NS_IMETHODIMP
996 nsThebesRenderingContext::RenderEPS(const nsRect& aRect, FILE *aDataFile)
998 return NS_ERROR_NOT_IMPLEMENTED;