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
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
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"
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"
55 #include "nsIThebesFontMetrics.h"
56 #include "nsThebesRegion.h"
57 #include "nsThebesImage.h"
59 #include <sys/types.h>
63 #include "gfxPlatform.h"
66 #include "gfxWindowsSurface.h"
67 #include "cairo-win32.h"
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
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
;
104 mThebes
= new gfxContext(aThebesSurface
);
106 return (CommonInit());
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
;
117 mThebes
= aThebesContext
;
119 return (CommonInit());
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
;
130 mThebes
= new gfxContext(aWidget
->GetThebesSurface());
132 //mThebes->SetColor(gfxRGBA(0.9, 0.0, 0.0, 0.3));
135 //mThebes->Translate(gfxPoint(300,0));
136 //mThebes->Rotate(M_PI/4);
138 return (CommonInit());
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();
154 nsThebesRenderingContext::GetDeviceContext(nsIDeviceContext
*& aDeviceContext
)
156 aDeviceContext
= mDeviceContext
;
157 NS_IF_ADDREF(aDeviceContext
);
162 nsThebesRenderingContext::PushTranslation(PushedTranslation
* aState
)
164 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::PushTranslation\n", this));
172 nsThebesRenderingContext::PopTranslation(PushedTranslation
* aState
)
174 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::PopTranslation\n", this));
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());
189 mThebes
->SetMatrix(newMat
);
194 nsThebesRenderingContext::PushState()
196 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::PushState\n", this));
203 nsThebesRenderingContext::PopState()
205 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::PopState\n", this));
216 nsThebesRenderingContext::SetClipRect(const nsRect
& aRect
,
217 nsClipCombine aCombine
)
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");
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
);
236 mThebes
->Rectangle(clipRect
);
245 nsThebesRenderingContext::SetClipRegion(const nsIRegion
& pxRegion
,
246 nsClipCombine aCombine
)
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
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
) {
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
));
272 mThebes
->Rectangle(gfxRect(x
, y
, w
, h
), PR_TRUE
);
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
);
284 for (PRUint32 i
= 0; i
< rects
->mNumRects
; i
++) {
285 mThebes
->Rectangle(gfxRect(rects
->mRects
[i
].x
,
287 rects
->mRects
[i
].width
,
288 rects
->mRects
[i
].height
),
293 evilPxRegion
->FreeRects (rects
);
296 mThebes
->SetMatrix(mat
);
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
);
312 case nsLineStyle_kDashed
:
313 mThebes
->SetDash(gfxContext::gfxLineDashed
);
315 case nsLineStyle_kDotted
:
316 mThebes
->SetDash(gfxContext::gfxLineDotted
);
318 case nsLineStyle_kNone
:
320 // nothing uses kNone
321 NS_ERROR("SetLineStyle: Invalid line style");
325 mLineStyle
= aLineStyle
;
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
));
344 nsThebesRenderingContext::GetColor(nscolor
&aColor
) const
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
)));
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
);
368 nsThebesRenderingContext::UpdateTempTransformMatrix()
370 //PR_LOG(gThebesGFXLog, PR_LOG_DEBUG, ("## %p nsTRC::UpdateTempTransformMatrix\n", this));
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 |
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
);
386 nsThebesRenderingContext::CurrentTransform()
388 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::CurrentTransform\n", this));
389 UpdateTempTransformMatrix();
390 return mTempTransform
;
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!
405 nsThebesRenderingContext::GetCurrentTransform(nsTransform2D
*&aTransform
)
407 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::GetCurrentTransform\n", this));
408 UpdateTempTransformMatrix();
409 aTransform
= &mTempTransform
;
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
);
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
);
444 mThebes
->IdentityMatrix();
448 // snap straight lines
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));
456 mThebes
->Line(p0
, p1
);
461 mThebes
->SetMatrix(savedMatrix
);
464 mThebes
->Line(p0
, p1
);
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
));
477 mThebes
->Rectangle(GFX_RECT_FROM_TWIPS_RECT(aRect
), PR_TRUE
);
484 nsThebesRenderingContext::DrawRect(nscoord aX
, nscoord aY
, nscoord aWidth
, nscoord aHeight
)
486 DrawRect(nsRect(aX
, aY
, aWidth
, aHeight
));
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,
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)
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
)
528 r
.size
.width
+= r
.pos
.x
;
529 if (r
.size
.width
< 0.0)
534 if (r
.pos
.x
+ r
.size
.width
> CAIRO_COORD_MAX
) {
535 r
.size
.width
= CAIRO_COORD_MAX
- r
.pos
.x
;
539 r
.size
.height
+= r
.pos
.y
;
540 if (r
.size
.height
< 0.0)
546 if (r
.pos
.y
+ r
.size
.height
> CAIRO_COORD_MAX
) {
547 r
.size
.height
= CAIRO_COORD_MAX
- r
.pos
.y
;
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
||
568 gfxMatrix mat
= mThebes
->CurrentMatrix();
570 r
= mat
.Transform(r
);
572 if (!ConditionRect(r
))
575 mThebes
->IdentityMatrix();
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
);
582 mThebes
->SetMatrix(mat
);
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
));
590 mThebes
->Rectangle(r
, PR_TRUE
);
597 nsThebesRenderingContext::FillRect(nscoord aX
, nscoord aY
, nscoord aWidth
, nscoord aHeight
)
599 FillRect(nsRect(aX
, aY
, aWidth
, aHeight
));
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
);
616 nsThebesRenderingContext::InvertRect(nscoord aX
, nscoord aY
, nscoord aWidth
, nscoord aHeight
)
618 return InvertRect(nsRect(aX
, aY
, aWidth
, aHeight
));
622 nsThebesRenderingContext::DrawEllipse(const nsRect
& aRect
)
624 return DrawEllipse(aRect
.x
, aRect
.y
, aRect
.width
, aRect
.height
);
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
));
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
)));
643 nsThebesRenderingContext::FillEllipse(const nsRect
& aRect
)
645 return FillEllipse(aRect
.x
, aRect
.y
, aRect
.width
, aRect
.height
);
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
));
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
)));
664 nsThebesRenderingContext::FillPolygon(const nsPoint twPoints
[], PRInt32 aNumPoints
)
666 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::FillPolygon %d\n", this, aNumPoints
));
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
);
682 mThebes
->Polygon(pxPoints
, aNumPoints
);
689 nsThebesRenderingContext::GetNativeGraphicData(GraphicDataType aType
)
691 if (aType
== NATIVE_GDK_DRAWABLE
)
694 return mWidget
->GetNativeData(NS_NATIVE_WIDGET
);
696 if (aType
== NATIVE_THEBES_CONTEXT
)
698 if (aType
== NATIVE_CAIRO_CONTEXT
)
699 return mThebes
->GetCairo();
701 if (aType
== NATIVE_WINDOWS_DC
) {
702 nsRefPtr
<gfxASurface
> surf(mThebes
->CurrentSurface());
703 if (!surf
|| surf
->CairoStatus())
705 return static_cast<gfxWindowsSurface
*>(static_cast<gfxASurface
*>(surf
.get()))->GetDC();
709 if (aType
== NATIVE_OS2_PS
) {
710 nsRefPtr
<gfxASurface
> surf(mThebes
->CurrentSurface());
711 if (!surf
|| surf
->CairoStatus())
713 return (void*)(static_cast<gfxOS2Surface
*>(static_cast<gfxASurface
*>(surf
.get()))->GetPS());
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
);
731 mThebes
->Clip(GFX_RECT_FROM_TWIPS_RECT(twRect
));
732 mThebes
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
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();
749 mThebes
->SetOperator(gfxContext::OPERATOR_SOURCE
);
752 mThebes
->SetOperator(gfxContext::OPERATOR_OVER
);
764 nsThebesRenderingContext::DrawTile(imgIContainer
*aImage
,
765 nscoord twXOffset
, nscoord twYOffset
,
766 const nsRect
*twTargetRect
,
767 const nsIntRect
*subimageRect
)
769 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::DrawTile %p %f %f [%f,%f,%f,%f]\n",
770 this, aImage
, FROM_TWIPS(twXOffset
), FROM_TWIPS(twYOffset
),
771 FROM_TWIPS(twTargetRect
->x
), FROM_TWIPS(twTargetRect
->y
),
772 FROM_TWIPS(twTargetRect
->width
), FROM_TWIPS(twTargetRect
->height
)));
774 nscoord containerWidth
, containerHeight
;
775 aImage
->GetWidth(&containerWidth
);
776 aImage
->GetHeight(&containerHeight
);
778 nsCOMPtr
<gfxIImageFrame
> imgFrame
;
779 aImage
->GetCurrentFrame(getter_AddRefs(imgFrame
));
780 if (!imgFrame
) return NS_ERROR_FAILURE
;
783 imgFrame
->GetRect(imgFrameRect
);
785 nsCOMPtr
<nsIImage
> img(do_GetInterface(imgFrame
));
786 if (!img
) return NS_ERROR_FAILURE
;
788 nsThebesImage
*thebesImage
= static_cast<nsThebesImage
*>((nsIImage
*) img
.get());
790 /* Phase offset of the repeated image from the origin */
791 gfxPoint
phase(FROM_TWIPS(twXOffset
), FROM_TWIPS(twYOffset
));
793 /* The image may be smaller than the container (bug 113561),
794 * so we need to make sure that there is the right amount of padding
795 * in between each tile of the nsIImage. This problem goes away
796 * when we change the way the GIF decoder works to have it store
797 * full frames that are ready to be composited.
799 PRInt32 xPadding
= 0;
800 PRInt32 yPadding
= 0;
802 nsIntRect tmpSubimageRect
;
804 tmpSubimageRect
= *subimageRect
;
806 tmpSubimageRect
= nsIntRect(0, 0, containerWidth
, containerHeight
);
809 if (imgFrameRect
.width
!= containerWidth
||
810 imgFrameRect
.height
!= containerHeight
)
812 xPadding
= containerWidth
- imgFrameRect
.width
;
813 yPadding
= containerHeight
- imgFrameRect
.height
;
815 // XXXroc shouldn't we be adding to 'phase' here? it's tbe origin
816 // at which the image origin should be drawn, and ThebesDrawTile
817 // just draws the origin of its "frame" there, so we should be
818 // adding imgFrameRect.x/y. so that the imgFrame draws in the
820 phase
.x
-= imgFrameRect
.x
;
821 phase
.y
-= imgFrameRect
.y
;
823 tmpSubimageRect
.x
-= imgFrameRect
.x
;
824 tmpSubimageRect
.y
-= imgFrameRect
.y
;
827 return thebesImage
->ThebesDrawTile (mThebes
, mDeviceContext
, phase
,
828 GFX_RECT_FROM_TWIPS_RECT(*twTargetRect
),
837 nsThebesRenderingContext::SetRightToLeftText(PRBool aIsRTL
)
839 return mFontMetrics
->SetRightToLeftText(aIsRTL
);
843 nsThebesRenderingContext::GetRightToLeftText(PRBool
* aIsRTL
)
845 *aIsRTL
= mFontMetrics
->GetRightToLeftText();
850 nsThebesRenderingContext::SetTextRunRTL(PRBool aIsRTL
)
852 mFontMetrics
->SetTextRunRTL(aIsRTL
);
856 nsThebesRenderingContext::SetFont(const nsFont
& aFont
, nsIAtom
* aLangGroup
)
858 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::SetFont %p\n", this, &aFont
));
860 nsCOMPtr
<nsIFontMetrics
> newMetrics
;
861 mDeviceContext
->GetMetricsFor(aFont
, aLangGroup
, *getter_AddRefs(newMetrics
));
862 mFontMetrics
= reinterpret_cast<nsIThebesFontMetrics
*>(newMetrics
.get());
867 nsThebesRenderingContext::SetFont(nsIFontMetrics
*aFontMetrics
)
869 PR_LOG(gThebesGFXLog
, PR_LOG_DEBUG
, ("## %p nsTRC::SetFont[Metrics] %p\n", this, aFontMetrics
));
871 mFontMetrics
= static_cast<nsIThebesFontMetrics
*>(aFontMetrics
);
876 nsThebesRenderingContext::GetFontMetrics(nsIFontMetrics
*&aFontMetrics
)
878 aFontMetrics
= mFontMetrics
;
879 NS_IF_ADDREF(aFontMetrics
);
884 nsThebesRenderingContext::GetMaxStringLength()
888 return mFontMetrics
->GetMaxStringLength();
892 nsThebesRenderingContext::GetWidth(char aC
, nscoord
&aWidth
)
894 if (aC
== ' ' && mFontMetrics
)
895 return mFontMetrics
->GetSpaceWidth(aWidth
);
897 return GetWidth(&aC
, 1, aWidth
);
901 nsThebesRenderingContext::GetWidth(PRUnichar aC
, nscoord
&aWidth
, PRInt32
*aFontID
)
903 return GetWidth(&aC
, 1, aWidth
, aFontID
);
907 nsThebesRenderingContext::GetWidthInternal(const char* aString
, PRUint32 aLength
, nscoord
& aWidth
)
910 aWidth
= (8 * aLength
);
919 return mFontMetrics
->GetWidth(aString
, aLength
, aWidth
, this);
923 nsThebesRenderingContext::GetWidthInternal(const PRUnichar
*aString
, PRUint32 aLength
,
924 nscoord
&aWidth
, PRInt32
*aFontID
)
927 aWidth
= (8 * aLength
);
936 return mFontMetrics
->GetWidth(aString
, aLength
, aWidth
, aFontID
, this);
940 nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString
, PRUint32 aLength
,
941 nsTextDimensions
& aDimensions
)
943 mFontMetrics
->GetMaxAscent(aDimensions
.ascent
);
944 mFontMetrics
->GetMaxDescent(aDimensions
.descent
);
945 return GetWidth(aString
, aLength
, aDimensions
.width
);
949 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar
* aString
,
951 nsTextDimensions
& aDimensions
,
954 mFontMetrics
->GetMaxAscent(aDimensions
.ascent
);
955 mFontMetrics
->GetMaxDescent(aDimensions
.descent
);
956 return GetWidth(aString
, aLength
, aDimensions
.width
, aFontID
);
959 #if defined(_WIN32) || defined(XP_OS2) || defined(MOZ_X11) || defined(XP_BEOS) || defined(XP_MACOSX) || defined (MOZ_DFB)
961 nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString
,
966 nsTextDimensions
& aDimensions
,
967 PRInt32
& aNumCharsFit
,
968 nsTextDimensions
& aLastWordDimensions
,
971 return NS_ERROR_NOT_IMPLEMENTED
;
975 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar
* aString
,
980 nsTextDimensions
& aDimensions
,
981 PRInt32
& aNumCharsFit
,
982 nsTextDimensions
& aLastWordDimensions
,
985 return NS_ERROR_NOT_IMPLEMENTED
;
991 nsThebesRenderingContext::GetBoundingMetricsInternal(const char* aString
,
993 nsBoundingMetrics
& aBoundingMetrics
)
995 return mFontMetrics
->GetBoundingMetrics(aString
, aLength
, this, aBoundingMetrics
);
999 nsThebesRenderingContext::GetBoundingMetricsInternal(const PRUnichar
* aString
,
1001 nsBoundingMetrics
& aBoundingMetrics
,
1004 return mFontMetrics
->GetBoundingMetrics(aString
, aLength
, this, aBoundingMetrics
);
1006 #endif // MOZ_MATHML
1009 nsThebesRenderingContext::DrawStringInternal(const char *aString
, PRUint32 aLength
,
1010 nscoord aX
, nscoord aY
,
1011 const nscoord
* aSpacing
)
1017 return mFontMetrics
->DrawString(aString
, aLength
, aX
, aY
, aSpacing
,
1022 nsThebesRenderingContext::DrawStringInternal(const PRUnichar
*aString
, PRUint32 aLength
,
1023 nscoord aX
, nscoord aY
,
1025 const nscoord
* aSpacing
)
1031 return mFontMetrics
->DrawString(aString
, aLength
, aX
, aY
, aFontID
,
1036 nsThebesRenderingContext::GetPosition(const PRUnichar
*aText
,
1044 nsThebesRenderingContext::GetRangeWidth(const PRUnichar
*aText
,
1050 return NS_ERROR_NOT_IMPLEMENTED
;
1054 nsThebesRenderingContext::GetRangeWidth(const char *aText
,
1060 return NS_ERROR_NOT_IMPLEMENTED
;
1064 nsThebesRenderingContext::RenderEPS(const nsRect
& aRect
, FILE *aDataFile
)
1066 return NS_ERROR_NOT_IMPLEMENTED
;