Bug 458861. Validate TrueType headers before activating downloaded font. r=roc, sr...
[wine-gecko.git] / gfx / src / thebes / nsThebesRenderingContext.cpp
blob16365d7f510aa3b5cf7b05435ebd8bc414cbc929
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;
763 NS_IMETHODIMP
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;
782 nsRect imgFrameRect;
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;
803 if (subimageRect) {
804 tmpSubimageRect = *subimageRect;
805 } else {
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
819 // right place.
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),
829 tmpSubimageRect,
830 xPadding, yPadding);
834 // text junk
836 NS_IMETHODIMP
837 nsThebesRenderingContext::SetRightToLeftText(PRBool aIsRTL)
839 return mFontMetrics->SetRightToLeftText(aIsRTL);
842 NS_IMETHODIMP
843 nsThebesRenderingContext::GetRightToLeftText(PRBool* aIsRTL)
845 *aIsRTL = mFontMetrics->GetRightToLeftText();
846 return NS_OK;
849 void
850 nsThebesRenderingContext::SetTextRunRTL(PRBool aIsRTL)
852 mFontMetrics->SetTextRunRTL(aIsRTL);
855 NS_IMETHODIMP
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());
863 return NS_OK;
866 NS_IMETHODIMP
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);
872 return NS_OK;
875 NS_IMETHODIMP
876 nsThebesRenderingContext::GetFontMetrics(nsIFontMetrics *&aFontMetrics)
878 aFontMetrics = mFontMetrics;
879 NS_IF_ADDREF(aFontMetrics);
880 return NS_OK;
883 PRInt32
884 nsThebesRenderingContext::GetMaxStringLength()
886 if (!mFontMetrics)
887 return 1;
888 return mFontMetrics->GetMaxStringLength();
891 NS_IMETHODIMP
892 nsThebesRenderingContext::GetWidth(char aC, nscoord &aWidth)
894 if (aC == ' ' && mFontMetrics)
895 return mFontMetrics->GetSpaceWidth(aWidth);
897 return GetWidth(&aC, 1, aWidth);
900 NS_IMETHODIMP
901 nsThebesRenderingContext::GetWidth(PRUnichar aC, nscoord &aWidth, PRInt32 *aFontID)
903 return GetWidth(&aC, 1, aWidth, aFontID);
906 NS_IMETHODIMP
907 nsThebesRenderingContext::GetWidthInternal(const char* aString, PRUint32 aLength, nscoord& aWidth)
909 #ifdef DISABLE_TEXT
910 aWidth = (8 * aLength);
911 return NS_OK;
912 #endif
914 if (aLength == 0) {
915 aWidth = 0;
916 return NS_OK;
919 return mFontMetrics->GetWidth(aString, aLength, aWidth, this);
922 NS_IMETHODIMP
923 nsThebesRenderingContext::GetWidthInternal(const PRUnichar *aString, PRUint32 aLength,
924 nscoord &aWidth, PRInt32 *aFontID)
926 #ifdef DISABLE_TEXT
927 aWidth = (8 * aLength);
928 return NS_OK;
929 #endif
931 if (aLength == 0) {
932 aWidth = 0;
933 return NS_OK;
936 return mFontMetrics->GetWidth(aString, aLength, aWidth, aFontID, this);
939 NS_IMETHODIMP
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);
948 NS_IMETHODIMP
949 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
950 PRUint32 aLength,
951 nsTextDimensions& aDimensions,
952 PRInt32* aFontID)
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)
960 NS_IMETHODIMP
961 nsThebesRenderingContext::GetTextDimensionsInternal(const char* aString,
962 PRInt32 aLength,
963 PRInt32 aAvailWidth,
964 PRInt32* aBreaks,
965 PRInt32 aNumBreaks,
966 nsTextDimensions& aDimensions,
967 PRInt32& aNumCharsFit,
968 nsTextDimensions& aLastWordDimensions,
969 PRInt32* aFontID)
971 return NS_ERROR_NOT_IMPLEMENTED;
974 NS_IMETHODIMP
975 nsThebesRenderingContext::GetTextDimensionsInternal(const PRUnichar* aString,
976 PRInt32 aLength,
977 PRInt32 aAvailWidth,
978 PRInt32* aBreaks,
979 PRInt32 aNumBreaks,
980 nsTextDimensions& aDimensions,
981 PRInt32& aNumCharsFit,
982 nsTextDimensions& aLastWordDimensions,
983 PRInt32* aFontID)
985 return NS_ERROR_NOT_IMPLEMENTED;
987 #endif
989 #ifdef MOZ_MATHML
990 NS_IMETHODIMP
991 nsThebesRenderingContext::GetBoundingMetricsInternal(const char* aString,
992 PRUint32 aLength,
993 nsBoundingMetrics& aBoundingMetrics)
995 return mFontMetrics->GetBoundingMetrics(aString, aLength, this, aBoundingMetrics);
998 NS_IMETHODIMP
999 nsThebesRenderingContext::GetBoundingMetricsInternal(const PRUnichar* aString,
1000 PRUint32 aLength,
1001 nsBoundingMetrics& aBoundingMetrics,
1002 PRInt32* aFontID)
1004 return mFontMetrics->GetBoundingMetrics(aString, aLength, this, aBoundingMetrics);
1006 #endif // MOZ_MATHML
1008 NS_IMETHODIMP
1009 nsThebesRenderingContext::DrawStringInternal(const char *aString, PRUint32 aLength,
1010 nscoord aX, nscoord aY,
1011 const nscoord* aSpacing)
1013 #ifdef DISABLE_TEXT
1014 return NS_OK;
1015 #endif
1017 return mFontMetrics->DrawString(aString, aLength, aX, aY, aSpacing,
1018 this);
1021 NS_IMETHODIMP
1022 nsThebesRenderingContext::DrawStringInternal(const PRUnichar *aString, PRUint32 aLength,
1023 nscoord aX, nscoord aY,
1024 PRInt32 aFontID,
1025 const nscoord* aSpacing)
1027 #ifdef DISABLE_TEXT
1028 return NS_OK;
1029 #endif
1031 return mFontMetrics->DrawString(aString, aLength, aX, aY, aFontID,
1032 aSpacing, this);
1035 PRInt32
1036 nsThebesRenderingContext::GetPosition(const PRUnichar *aText,
1037 PRUint32 aLength,
1038 nsPoint aPt)
1040 return -1;
1043 NS_IMETHODIMP
1044 nsThebesRenderingContext::GetRangeWidth(const PRUnichar *aText,
1045 PRUint32 aLength,
1046 PRUint32 aStart,
1047 PRUint32 aEnd,
1048 PRUint32 &aWidth)
1050 return NS_ERROR_NOT_IMPLEMENTED;
1053 NS_IMETHODIMP
1054 nsThebesRenderingContext::GetRangeWidth(const char *aText,
1055 PRUint32 aLength,
1056 PRUint32 aStart,
1057 PRUint32 aEnd,
1058 PRUint32 &aWidth)
1060 return NS_ERROR_NOT_IMPLEMENTED;
1063 NS_IMETHODIMP
1064 nsThebesRenderingContext::RenderEPS(const nsRect& aRect, FILE *aDataFile)
1066 return NS_ERROR_NOT_IMPLEMENTED;