2
* Copyright (C) 2007-2009 Torch Mobile Inc.
3
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Library General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Library General Public License for more details.
15
* You should have received a copy of the GNU Library General Public License
16
* along with this library; see the file COPYING.LIB. If not, write to
17
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
23
#include "GraphicsContext.h"
25
#include "AffineTransform.h"
27
#include "GDIExtras.h"
28
#include "GlyphBuffer.h"
30
#include "NotImplemented.h"
32
#include "PlatformPathWinCE.h"
33
#include "SharedBitmap.h"
34
#include "SimpleFontData.h"
36
#include <wtf/OwnPtr.h>
37
#include <wtf/unicode/CharacterNames.h>
41
typedef void (*FuncGradientFillRectLinear)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, const Vector<Gradient::ColorStop>& stops);
42
typedef void (*FuncGradientFillRectRadial)(HDC hdc, const IntRect& r, const IntPoint& p0, const IntPoint& p1, float r0, float r1, const Vector<Gradient::ColorStop>& stops);
43
FuncGradientFillRectLinear g_linearGradientFiller = 0;
44
FuncGradientFillRectRadial g_radialGradientFiller = 0;
46
static inline bool isZero(double d)
48
return d > 0 ? d <= 1.E-10 : d >= -1.E-10;
51
// stableRound rounds -0.5 to 0, where lround rounds -0.5 to -1.
52
static inline int stableRound(double d)
55
return static_cast<int>(d + 0.5);
57
int i = static_cast<int>(d);
58
return i - d > 0.5 ? i - 1 : i;
61
// Unlike enclosingIntRect(), this function does strict rounding.
62
static inline IntRect roundRect(const FloatRect& r)
64
return IntRect(stableRound(r.x()), stableRound(r.y()), stableRound(r.maxX()) - stableRound(r.x()), stableRound(r.maxY()) - stableRound(r.y()));
67
// Rotation transformation
68
class RotationTransform {
79
RotationTransform operator-() const
81
RotationTransform rtn;
84
rtn.m_preShiftX = m_postShiftX;
85
rtn.m_preShiftY = m_postShiftY;
86
rtn.m_postShiftX = m_preShiftX;
87
rtn.m_postShiftY = m_preShiftY;
90
void map(double x1, double y1, double* x2, double* y2) const
94
*x2 = x1 * m_cosA + y1 * m_sinA + m_postShiftX;
95
*y2 = y1 * m_cosA - x1 * m_sinA + m_postShiftY;
97
void map(int x1, int y1, int* x2, int* y2) const
101
*x2 = stableRound(x1 * m_cosA + y1 * m_sinA) + m_postShiftX;
102
*y2 = stableRound(y1 * m_cosA - x1 * m_sinA) + m_postShiftY;
113
template<class T> static inline IntPoint mapPoint(const IntPoint& p, const T& t)
116
t.map(p.x(), p.y(), &x, &y);
117
return IntPoint(x, y);
120
template<class T> static inline FloatPoint mapPoint(const FloatPoint& p, const T& t)
123
t.map(p.x(), p.y(), &x, &y);
124
return FloatPoint(static_cast<float>(x), static_cast<float>(y));
127
template<class Transform, class Rect, class Value> static inline Rect mapRect(const Rect& rect, const Transform& transform)
133
transform.map(rect.x(), rect.y(), x, y);
134
transform.map(rect.x(), b, x + 1, y + 1);
135
transform.map(r, b, x + 2, y + 2);
136
transform.map(r, rect.y(), x + 3, y + 3);
139
for (int i = 0; i < 3; ++i) {
151
return IntRect(l, t, r - l + 1, b - t + 1);
154
template<class T> static inline IntRect mapRect(const IntRect& rect, const T& transform)
156
return mapRect<T, IntRect, int>(rect, transform);
159
template<class T> static inline FloatRect mapRect(const FloatRect& rect, const T& transform)
161
return mapRect<T, FloatRect, double>(rect, transform);
164
class GraphicsContextPlatformPrivateData {
166
GraphicsContextPlatformPrivateData()
172
AffineTransform m_transform;
176
enum AlphaPaintType {
182
class GraphicsContextPlatformPrivate : public GraphicsContextPlatformPrivateData {
184
GraphicsContextPlatformPrivate(HDC dc)
188
~GraphicsContextPlatformPrivate()
190
while (!m_backupData.isEmpty())
194
void translate(float x, float y)
196
m_transform.translate(x, y);
199
void scale(const FloatSize& size)
201
m_transform.scaleNonUniform(size.width(), size.height());
204
void rotate(float radians)
206
m_transform.rotate(rad2deg(radians));
209
void concatCTM(const AffineTransform& transform)
211
m_transform *= transform;
214
void setCTM(const AffineTransform& transform)
216
m_transform = transform;
219
IntRect mapRect(const IntRect& rect) const
221
return m_transform.mapRect(rect);
224
FloatRect mapRect(const FloatRect& rect) const
226
return m_transform.mapRect(rect);
229
IntPoint mapPoint(const IntPoint& point) const
231
return m_transform.mapPoint(point);
234
FloatPoint mapPoint(const FloatPoint& point) const
236
return m_transform.mapPoint(point);
239
FloatSize mapSize(const FloatSize& size) const
242
m_transform.map(size.width(), size.height(), w, h);
243
return FloatSize(static_cast<float>(w), static_cast<float>(h));
251
m_backupData.append(*static_cast<GraphicsContextPlatformPrivateData*>(this));
256
if (m_backupData.isEmpty())
262
GraphicsContextPlatformPrivateData::operator=(m_backupData.last());
263
m_backupData.removeLast();
266
bool hasAlpha() const { return m_bitmap && m_bitmap->hasAlpha(); }
268
PassRefPtr<SharedBitmap> getTransparentLayerBitmap(IntRect& origRect, AlphaPaintType alphaPaint, RECT& bmpRect, bool checkClipBox, bool force) const
273
if (force || m_opacity < 1.) {
276
int clipType = GetClipBox(m_dc, &clipBox);
277
if (clipType == SIMPLEREGION || clipType == COMPLEXREGION)
278
origRect.intersect(clipBox);
279
if (origRect.isEmpty())
283
RefPtr<SharedBitmap> bmp = SharedBitmap::create(origRect.size(), alphaPaint == AlphaPaintNone ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, false);
284
SetRect(&bmpRect, 0, 0, origRect.width(), origRect.height());
286
switch (alphaPaint) {
288
case AlphaPaintImage:
290
SharedBitmap::DCHolder dc(bmp.get());
292
BitBlt(dc.get(), 0, 0, origRect.width(), origRect.height(), m_dc, origRect.x(), origRect.y(), SRCCOPY);
293
if (bmp->is32bit() && (!m_bitmap || m_bitmap->is16bit())) {
295
unsigned* pixels = (unsigned*)bmp->bytes();
296
const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
297
while (pixels < pixelsEnd) {
298
*pixels |= 0xFF000000;
306
//case AlphaPaintOther:
308
memset(bmp->bytes(), 0xFF, bmp->bitmapInfo().numPixels() * 4);
319
void paintBackTransparentLayerBitmap(HDC hdc, SharedBitmap* bmp, const IntRect& origRect, AlphaPaintType alphaPaint, const RECT& bmpRect)
324
if (alphaPaint == AlphaPaintOther && hasAlphaBlendSupport()) {
325
ASSERT(bmp && bmp->bytes() && bmp->is32bit());
326
unsigned* pixels = (unsigned*)bmp->bytes();
327
const unsigned* const pixelsEnd = pixels + bmp->bitmapInfo().numPixels();
328
while (pixels < pixelsEnd) {
329
*pixels ^= 0xFF000000;
333
if ((m_opacity < 1. || alphaPaint == AlphaPaintOther) && hasAlphaBlendSupport()) {
334
const BLENDFUNCTION blend = { AC_SRC_OVER, 0
335
, m_opacity >= 1. ? 255 : (BYTE)(m_opacity * 255)
336
, alphaPaint == AlphaPaintNone ? 0 : AC_SRC_ALPHA };
337
bool success = alphaBlendIfSupported(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, blend);
338
ASSERT_UNUSED(success, success);
340
StretchBlt(m_dc, origRect.x(), origRect.y(), origRect.width(), origRect.height(), hdc, 0, 0, bmpRect.right, bmpRect.bottom, SRCCOPY);
344
RefPtr<SharedBitmap> m_bitmap;
345
Vector<GraphicsContextPlatformPrivateData> m_backupData;
348
static PassOwnPtr<HPEN> createPen(const Color& col, double fWidth, StrokeStyle style)
350
int width = stableRound(fWidth);
354
int penStyle = PS_NULL;
357
#if ENABLE(CSS3_TEXT)
359
case WavyStroke: // FIXME: https://bugs.webkit.org/show_bug.cgi?id=94114 - Needs platform support.
363
case DottedStroke: // not supported on Windows CE
372
return adoptPtr(CreatePen(penStyle, width, RGB(col.red(), col.green(), col.blue())));
375
static inline PassOwnPtr<HBRUSH> createBrush(const Color& col)
377
return adoptPtr(CreateSolidBrush(RGB(col.red(), col.green(), col.blue())));
380
template <typename PixelType, bool Is16bit> static void _rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
382
int destW = destBmp->width();
383
int destH = destBmp->height();
384
int sourceW = sourceBmp->width();
385
int sourceH = sourceBmp->height();
386
PixelType* dest = (PixelType*)destBmp->bytes();
387
const PixelType* source = (const PixelType*)sourceBmp->bytes();
392
paddedSourceW = sourceW + (sourceW & 1);
395
paddedSourceW = sourceW;
397
if (isZero(transform.m_sinA)) {
398
int cosA = transform.m_cosA > 0 ? 1 : -1;
399
for (int y = 0; y < destH; ++y) {
400
for (int x = 0; x < destW; ++x) {
401
int x1 = x + transform.m_preShiftX;
402
int y1 = y + transform.m_preShiftY;
403
int srcX = x1 * cosA + transform.m_postShiftX;
404
int srcY = y1 * cosA - transform.m_postShiftY;
405
if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
406
*dest++ = source[srcY * paddedSourceW + srcX] | 0xFF000000;
412
} else if (isZero(transform.m_cosA)) {
413
int sinA = transform.m_sinA > 0 ? 1 : -1;
414
for (int y = 0; y < destH; ++y) {
415
for (int x = 0; x < destW; ++x) {
416
int x1 = x + transform.m_preShiftX;
417
int y1 = y + transform.m_preShiftY;
418
int srcX = y1 * sinA + transform.m_postShiftX;
419
int srcY = -x1 * sinA + transform.m_postShiftY;
420
if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
421
*dest++ = source[srcY * paddedSourceW + srcX];
426
for (int y = 0; y < destH; ++y) {
427
for (int x = 0; x < destW; ++x) {
428
// FIXME: for best quality, we should get weighted sum of four neighbours,
429
// but that will be too expensive
431
transform.map(x, y, &srcX, &srcY);
432
if (srcX >= 0 && srcX <= sourceW && srcY >= 0 && srcY <= sourceH)
433
*dest++ = source[srcY * paddedSourceW + srcX];
440
static void rotateBitmap(SharedBitmap* destBmp, const SharedBitmap* sourceBmp, const RotationTransform& transform)
442
ASSERT(destBmp->is16bit() == sourceBmp->is16bit());
443
if (destBmp->is16bit())
444
_rotateBitmap<unsigned short, true>(destBmp, sourceBmp, transform);
446
_rotateBitmap<unsigned, false>(destBmp, sourceBmp, transform);
449
class TransparentLayerDC {
450
WTF_MAKE_NONCOPYABLE(TransparentLayerDC);
452
TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform = 0, int alpha = 255, bool paintImage = false);
453
~TransparentLayerDC();
455
HDC hdc() const { return m_memDc; }
456
const RECT& rect() const { return m_bmpRect; }
457
IntSize toShift() const { return IntSize(m_bmpRect.left - m_origRect.x(), m_bmpRect.top - m_origRect.y()); }
458
void fillAlphaChannel();
461
GraphicsContextPlatformPrivate* m_data;
463
IntRect m_rotatedOrigRect;
465
RefPtr<SharedBitmap> m_bitmap;
466
RefPtr<SharedBitmap> m_rotatedBitmap;
469
RotationTransform m_rotation;
471
AlphaPaintType m_alphaPaintType;
474
TransparentLayerDC::TransparentLayerDC(GraphicsContextPlatformPrivate* data, IntRect& origRect, const IntRect* rectBeforeTransform, int alpha, bool paintImage)
476
, m_origRect(origRect)
477
, m_oldOpacity(data->m_opacity)
478
// m_key1 and m_key2 are not initalized here. They are used only in the case that
479
// SharedBitmap::getDC() is called, I.E., when m_bitmap is not null.
481
m_data->m_opacity *= alpha / 255.;
482
bool mustCreateLayer;
483
if (!m_data->hasAlpha()) {
484
mustCreateLayer = false;
485
m_alphaPaintType = AlphaPaintNone;
487
mustCreateLayer = true;
488
m_alphaPaintType = paintImage ? AlphaPaintImage : AlphaPaintOther;
490
if (rectBeforeTransform && !isZero(m_data->m_transform.b())) {
491
m_rotatedOrigRect = origRect;
492
m_rotatedBitmap = m_data->getTransparentLayerBitmap(m_rotatedOrigRect, m_alphaPaintType, m_bmpRect, false, true);
493
if (m_rotatedBitmap) {
494
double a = m_data->m_transform.a();
495
double b = m_data->m_transform.b();
496
double c = _hypot(a, b);
497
m_rotation.m_cosA = a / c;
498
m_rotation.m_sinA = b / c;
500
int centerX = origRect.x() + origRect.width() / 2;
501
int centerY = origRect.y() + origRect.height() / 2;
502
m_rotation.m_preShiftX = -centerX;
503
m_rotation.m_preShiftY = -centerY;
504
m_rotation.m_postShiftX = centerX;
505
m_rotation.m_postShiftY = centerY;
507
m_origRect = mapRect(m_rotatedOrigRect, m_rotation);
509
m_rotation.m_preShiftX += m_rotatedOrigRect.x();
510
m_rotation.m_preShiftY += m_rotatedOrigRect.y();
511
m_rotation.m_postShiftX -= m_origRect.x();
512
m_rotation.m_postShiftY -= m_origRect.y();
514
FloatPoint topLeft = m_data->m_transform.mapPoint(FloatPoint(rectBeforeTransform->location()));
515
FloatPoint topRight(rectBeforeTransform->maxX() - 1, rectBeforeTransform->y());
516
topRight = m_data->m_transform.mapPoint(topRight);
517
FloatPoint bottomLeft(rectBeforeTransform->x(), rectBeforeTransform->maxY() - 1);
518
bottomLeft = m_data->m_transform.mapPoint(bottomLeft);
519
FloatSize sideTop = topRight - topLeft;
520
FloatSize sideLeft = bottomLeft - topLeft;
521
float width = _hypot(sideTop.width() + 1, sideTop.height() + 1);
522
float height = _hypot(sideLeft.width() + 1, sideLeft.height() + 1);
524
origRect.inflateX(stableRound((width - origRect.width()) * 0.5));
525
origRect.inflateY(stableRound((height - origRect.height()) * 0.5));
527
m_bitmap = SharedBitmap::create(m_origRect.size(), m_rotatedBitmap->is16bit() ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32, true);
529
rotateBitmap(m_bitmap.get(), m_rotatedBitmap.get(), -m_rotation);
534
m_bitmap = m_data->getTransparentLayerBitmap(m_origRect, m_alphaPaintType, m_bmpRect, true, mustCreateLayer);
536
m_memDc = m_bitmap->getDC(&m_key);
538
m_memDc = m_data->m_dc;
541
TransparentLayerDC::~TransparentLayerDC()
543
if (m_rotatedBitmap) {
544
m_bitmap->releaseDC(m_memDc, m_key);
546
rotateBitmap(m_rotatedBitmap.get(), m_bitmap.get(), m_rotation);
547
m_memDc = m_rotatedBitmap->getDC(&m_key);
548
m_data->paintBackTransparentLayerBitmap(m_memDc, m_rotatedBitmap.get(), m_rotatedOrigRect, m_alphaPaintType, m_bmpRect);
549
m_rotatedBitmap->releaseDC(m_memDc, m_key);
550
} else if (m_bitmap) {
551
m_data->paintBackTransparentLayerBitmap(m_memDc, m_bitmap.get(), m_origRect, m_alphaPaintType, m_bmpRect);
552
m_bitmap->releaseDC(m_memDc, m_key);
554
m_data->m_opacity = m_oldOpacity;
557
void TransparentLayerDC::fillAlphaChannel()
559
if (!m_bitmap || !m_bitmap->is32bit())
562
unsigned* pixels = (unsigned*)m_bitmap->bytes();
563
const unsigned* const pixelsEnd = pixels + m_bitmap->bitmapInfo().numPixels();
564
while (pixels < pixelsEnd) {
565
*pixels |= 0xFF000000;
570
class ScopeDCProvider {
571
WTF_MAKE_NONCOPYABLE(ScopeDCProvider);
573
explicit ScopeDCProvider(GraphicsContextPlatformPrivate* data)
576
if (m_data->m_bitmap)
577
m_data->m_dc = m_data->m_bitmap->getDC(&m_key);
581
if (m_data->m_bitmap) {
582
m_data->m_bitmap->releaseDC(m_data->m_dc, m_key);
587
GraphicsContextPlatformPrivate* m_data;
592
void GraphicsContext::platformInit(PlatformGraphicsContext* dc)
594
m_data = new GraphicsContextPlatformPrivate(dc);
597
void GraphicsContext::platformDestroy()
602
void GraphicsContext::setBitmap(PassRefPtr<SharedBitmap> bmp)
604
ASSERT(!m_data->m_dc);
605
m_data->m_bitmap = bmp;
608
HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
610
// FIXME: Add support for AlphaBlend.
611
ASSERT(!supportAlphaBlend);
615
void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
619
void GraphicsContext::savePlatformState()
624
void GraphicsContext::restorePlatformState()
629
void GraphicsContext::drawRect(const IntRect& rect)
631
if (!m_data->m_opacity || paintingDisabled() || rect.isEmpty())
634
ScopeDCProvider dcProvider(m_data);
638
IntRect trRect = m_data->mapRect(rect);
639
TransparentLayerDC transparentDC(m_data, trRect, &rect);
640
HDC dc = transparentDC.hdc();
643
trRect.move(transparentDC.toShift());
645
OwnPtr<HBRUSH> brush;
647
if (fillColor().alpha()) {
648
brush = createBrush(fillColor());
649
oldBrush = SelectObject(dc, brush.get());
651
oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
655
if (strokeStyle() != NoStroke) {
656
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
657
oldPen = SelectObject(dc, pen.get());
659
oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
662
if (trRect.width() <= 0)
664
if (trRect.height() <= 0)
667
Rectangle(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
670
SelectObject(dc, oldPen);
671
SelectObject(dc, oldBrush);
674
void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
676
if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || !strokeColor().alpha())
679
ScopeDCProvider dcProvider(m_data);
683
IntPoint trPoint1 = m_data->mapPoint(point1);
684
IntPoint trPoint2 = m_data->mapPoint(point2);
686
IntRect lineRect(trPoint1, trPoint2 - trPoint1);
687
lineRect.setHeight(lineRect.height() + strokeThickness());
688
TransparentLayerDC transparentDC(m_data, lineRect, 0, strokeColor().alpha());
689
HDC dc = transparentDC.hdc();
692
trPoint1 += transparentDC.toShift();
693
trPoint2 += transparentDC.toShift();
695
OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
696
HGDIOBJ oldPen = SelectObject(dc, pen.get());
698
MoveToEx(dc, trPoint1.x(), trPoint1.y(), 0);
699
LineTo(dc, trPoint2.x(), trPoint2.y());
701
SelectObject(dc, oldPen);
704
void GraphicsContext::drawEllipse(const IntRect& rect)
706
if (!m_data->m_opacity || paintingDisabled() || (!fillColor().alpha() && strokeStyle() == NoStroke))
709
ScopeDCProvider dcProvider(m_data);
713
IntRect trRect = m_data->mapRect(rect);
714
TransparentLayerDC transparentDC(m_data, trRect, &rect);
715
HDC dc = transparentDC.hdc();
718
trRect.move(transparentDC.toShift());
720
OwnPtr<HBRUSH> brush;
722
if (fillColor().alpha()) {
723
brush = createBrush(fillColor());
724
oldBrush = SelectObject(dc, brush.get());
726
oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
730
if (strokeStyle() != NoStroke) {
731
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
732
oldPen = SelectObject(dc, pen.get());
734
oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
737
Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
739
SelectObject(dc, oldPen);
740
SelectObject(dc, oldBrush);
743
static inline bool equalAngle(double a, double b)
745
return fabs(a - b) < 1E-5;
748
void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y)
751
angle += 2 * piDouble;
752
while (angle >= 2 * piDouble)
753
angle -= 2 * piDouble;
755
if (equalAngle(angle, 0) || equalAngle(angle, 2 * piDouble)) {
758
} else if (equalAngle(angle, piDouble)) {
761
} else if (equalAngle(angle, .5 * piDouble)) {
764
} else if (equalAngle(angle, 1.5 * piDouble)) {
768
double k = tan(angle);
771
double tmp = 1. / (1. / sqA + (k * k) / sqB);
772
tmp = tmp <= 0 ? 0 : sqrt(tmp);
773
if (angle > .5 * piDouble && angle < 1.5 * piDouble)
777
k = tan(.5 * piDouble - angle);
778
tmp = 1. / ((k * k) / sqA + 1 / sqB);
779
tmp = tmp <= 0 ? 0 : sqrt(tmp);
780
if (angle > piDouble)
786
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
788
if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke || rect.isEmpty())
791
ScopeDCProvider dcProvider(m_data);
795
IntRect trRect = m_data->mapRect(rect);
796
TransparentLayerDC transparentDC(m_data, trRect, &rect);
797
HDC dc = transparentDC.hdc();
800
trRect.move(transparentDC.toShift());
802
OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
803
HGDIOBJ oldPen = SelectObject(dc, pen.get());
805
double a = trRect.width() * 0.5;
806
double b = trRect.height() * 0.5;
807
int centerX = stableRound(trRect.x() + a);
808
int centerY = stableRound(trRect.y() + b);
809
float fstartX, fstartY, fendX, fendY;
810
int startX, startY, endX, endY;
811
getEllipsePointByAngle(deg2rad((double)startAngle), a, b, fstartX, fstartY);
812
getEllipsePointByAngle(deg2rad((double)startAngle + angleSpan), a, b, fendX, fendY);
813
startX = stableRound(fstartX);
814
startY = stableRound(fstartY);
815
endX = stableRound(fendX);
816
endY = stableRound(fendY);
819
startY = centerY - startY;
821
endY = centerY - endY;
824
clipRect.left = startX;
825
clipRect.right = endX;
827
clipRect.left = endX;
828
clipRect.right = startX;
831
clipRect.top = startY;
832
clipRect.bottom = endY;
835
clipRect.bottom = startY;
838
OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
840
if (GetClipRgn(dc, clipRgn.get()) <= 0) {
842
clipRgn = adoptPtr(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
843
SelectClipRgn(dc, clipRgn.get());
846
IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
849
HGDIOBJ oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
850
Ellipse(dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
851
SelectObject(dc, oldBrush);
854
SelectClipRgn(dc, 0);
856
SelectClipRgn(dc, clipRgn.get());
858
SelectObject(dc, oldPen);
861
void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
863
if (!m_data->m_opacity || paintingDisabled() || npoints <= 1 || !points)
866
ScopeDCProvider dcProvider(m_data);
870
Vector<POINT, 20> winPoints(npoints);
871
FloatPoint trPoint = m_data->mapPoint(points[0]);
872
winPoints[0].x = stableRound(trPoint.x());
873
winPoints[0].y = stableRound(trPoint.y());
874
RECT rect = { winPoints[0].x, winPoints[0].y, winPoints[0].x, winPoints[0].y };
875
for (size_t i = 1; i < npoints; ++i) {
876
trPoint = m_data->mapPoint(points[i]);
877
winPoints[i].x = stableRound(trPoint.x());
878
winPoints[i].y = stableRound(trPoint.y());
879
if (rect.left > winPoints[i].x)
880
rect.left = winPoints[i].x;
881
else if (rect.right < winPoints[i].x)
882
rect.right = winPoints[i].x;
883
if (rect.top > winPoints[i].y)
884
rect.top = winPoints[i].y;
885
else if (rect.bottom < winPoints[i].y)
886
rect.bottom = winPoints[i].y;
891
IntRect intRect(rect);
892
TransparentLayerDC transparentDC(m_data, intRect);
893
HDC dc = transparentDC.hdc();
897
for (size_t i = 0; i < npoints; ++i) {
898
winPoints[i].x += transparentDC.toShift().width();
899
winPoints[i].y += transparentDC.toShift().height();
902
OwnPtr<HBRUSH> brush;
904
if (fillColor().alpha()) {
905
brush = createBrush(fillColor());
906
oldBrush = SelectObject(dc, brush.get());
908
oldBrush = SelectObject(dc, GetStockObject(NULL_BRUSH));
912
if (strokeStyle() != NoStroke) {
913
pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
914
oldPen = SelectObject(dc, pen.get());
916
oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
919
Polygon(dc, winPoints.data(), npoints);
921
SelectObject(dc, oldPen);
922
SelectObject(dc, oldBrush);
925
void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
927
if (paintingDisabled())
933
// FIXME: IMPLEMENT!!
936
void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
938
if (paintingDisabled() || !m_data->m_opacity)
941
int alpha = color.alpha();
945
ScopeDCProvider dcProvider(m_data);
949
IntRect intRect = enclosingIntRect(rect);
950
TransparentLayerDC transparentDC(m_data, m_data->mapRect(intRect), &intRect, alpha);
952
if (!transparentDC.hdc())
955
OwnPtr<HBRUSH> hbrush = adoptPtr(CreateSolidBrush(RGB(color.red(), color.green(), color.blue())));
956
FillRect(transparentDC.hdc(), &transparentDC.rect(), hbrush.get());
959
void GraphicsContext::clip(const FloatRect& rect)
961
if (paintingDisabled())
967
IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
969
OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
970
if (GetClipRgn(m_data->m_dc, clipRgn.get()) > 0)
971
IntersectClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
973
clipRgn = adoptPtr(CreateRectRgn(trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY()));
974
SelectClipRgn(m_data->m_dc, clipRgn.get());
978
void GraphicsContext::clipOut(const IntRect& rect)
980
if (paintingDisabled())
986
IntRect trRect = m_data->mapRect(rect);
988
ExcludeClipRect(m_data->m_dc, trRect.x(), trRect.y(), trRect.maxX(), trRect.maxY());
991
void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
996
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
998
if (!m_data->m_opacity || paintingDisabled())
1001
ScopeDCProvider dcProvider(m_data);
1005
int radius = (width - 1) / 2;
1008
unsigned rectCount = rects.size();
1009
IntRect finalFocusRect;
1010
for (unsigned i = 0; i < rectCount; i++) {
1011
IntRect focusRect = rects[i];
1012
focusRect.inflate(offset);
1013
finalFocusRect.unite(focusRect);
1016
IntRect intRect = finalFocusRect;
1017
IntRect trRect = m_data->mapRect(finalFocusRect);
1018
TransparentLayerDC transparentDC(m_data, trRect, &intRect);
1019
HDC dc = transparentDC.hdc();
1022
trRect.move(transparentDC.toShift());
1025
DrawFocusRect(dc, &rect);
1028
void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing)
1030
if (paintingDisabled())
1033
StrokeStyle oldStyle = strokeStyle();
1034
setStrokeStyle(SolidStroke);
1035
drawLine(roundedIntPoint(origin), roundedIntPoint(origin + FloatSize(width, 0)));
1036
setStrokeStyle(oldStyle);
1039
void GraphicsContext::drawLineForDocumentMarker(const FloatPoint&, float width, DocumentMarkerLineStyle style)
1044
void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace colorSpace)
1049
void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace colorSpace)
1054
void GraphicsContext::setPlatformStrokeThickness(float strokeThickness)
1059
void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
1064
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
1066
// We can only clip rectangles on WINCE
1070
void GraphicsContext::clearRect(const FloatRect& rect)
1072
if (paintingDisabled())
1075
if (m_data->hasAlpha()) {
1076
IntRect trRect = enclosingIntRect(m_data->mapRect(rect));
1077
m_data->m_bitmap->clearPixels(trRect);
1081
fillRect(rect, Color(Color::white), ColorSpaceDeviceRGB);
1084
void GraphicsContext::strokeRect(const FloatRect& rect, float width)
1086
if (!m_data->m_opacity || paintingDisabled() || strokeStyle() == NoStroke)
1089
ScopeDCProvider dcProvider(m_data);
1093
IntRect intRect = enclosingIntRect(rect);
1094
IntRect trRect = m_data->mapRect(intRect);
1095
TransparentLayerDC transparentDC(m_data, trRect, &intRect);
1096
HDC dc = transparentDC.hdc();
1099
trRect.move(transparentDC.toShift());
1101
OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
1102
HGDIOBJ oldPen = SelectObject(dc, pen.get());
1104
int right = trRect.maxX() - 1;
1105
int bottom = trRect.maxY() - 1;
1106
const POINT intPoints[5] =
1108
{ trRect.x(), trRect.y() },
1109
{ right, trRect.y() },
1111
{ trRect.x(), bottom },
1112
{ trRect.x(), trRect.y() }
1115
Polyline(dc, intPoints, 5);
1117
SelectObject(dc, oldPen);
1120
void GraphicsContext::beginPlatformTransparencyLayer(float opacity)
1123
m_data->m_opacity *= opacity;
1126
void GraphicsContext::endPlatformTransparencyLayer()
1131
bool GraphicsContext::supportsTransparencyLayers()
1136
void GraphicsContext::concatCTM(const AffineTransform& transform)
1138
m_data->concatCTM(transform);
1141
void GraphicsContext::setCTM(const AffineTransform& transform)
1143
m_data->setCTM(transform);
1146
AffineTransform& GraphicsContext::affineTransform()
1148
return m_data->m_transform;
1151
const AffineTransform& GraphicsContext::affineTransform() const
1153
return m_data->m_transform;
1156
void GraphicsContext::resetAffineTransform()
1158
m_data->m_transform.makeIdentity();
1161
void GraphicsContext::translate(float x, float y)
1163
m_data->translate(x, y);
1166
void GraphicsContext::rotate(float radians)
1168
m_data->rotate(radians);
1171
void GraphicsContext::scale(const FloatSize& size)
1173
m_data->scale(size);
1176
void GraphicsContext::setLineCap(LineCap lineCap)
1181
void GraphicsContext::setLineJoin(LineJoin lineJoin)
1186
void GraphicsContext::setMiterLimit(float miter)
1191
void GraphicsContext::setAlpha(float alpha)
1193
m_data->m_opacity = alpha;
1196
void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
1201
void GraphicsContext::clip(const Path& path)
1206
void GraphicsContext::canvasClip(const Path& path)
1211
void GraphicsContext::clipOut(const Path&)
1216
static inline IntPoint rectCenterPoint(const RECT& rect)
1218
return IntPoint(rect.left + (rect.right - rect.left) / 2, rect.top + (rect.bottom - rect.top) / 2);
1220
void GraphicsContext::fillRoundedRect(const IntRect& fillRect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& c, ColorSpace colorSpace)
1222
ScopeDCProvider dcProvider(m_data);
1226
FloatSize shadowOffset;
1227
float shadowBlur = 0;
1229
ColorSpace shadowColorSpace;
1231
getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace);
1233
IntRect dstRect = fillRect;
1235
dstRect.move(stableRound(shadowOffset.width()), stableRound(shadowOffset.height()));
1236
dstRect.inflate(stableRound(shadowBlur));
1237
dstRect = m_data->mapRect(dstRect);
1239
FloatSize newTopLeft(m_data->mapSize(topLeft));
1240
FloatSize newTopRight(m_data->mapSize(topRight));
1241
FloatSize newBottomLeft(m_data->mapSize(bottomLeft));
1242
FloatSize newBottomRight(m_data->mapSize(bottomRight));
1244
TransparentLayerDC transparentDc(m_data, dstRect, &fillRect);
1245
HDC dc = transparentDc.hdc();
1249
dstRect.move(transparentDc.toShift());
1251
RECT rectWin = dstRect;
1253
OwnPtr<HBRUSH> brush = createBrush(shadowColor);
1254
HGDIOBJ oldBrush = SelectObject(dc, brush.get());
1256
SelectObject(dc, GetStockObject(NULL_PEN));
1258
IntPoint centerPoint = rectCenterPoint(rectWin);
1259
// Draw top left half
1260
RECT clipRect(rectWin);
1261
clipRect.right = centerPoint.x();
1262
clipRect.bottom = centerPoint.y();
1264
OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
1265
bool needsNewClip = (GetClipRgn(dc, clipRgn.get()) <= 0);
1267
drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopLeft.width() * 2), stableRound(newTopLeft.height() * 2));
1271
clipRect.left = centerPoint.x();
1272
clipRect.bottom = centerPoint.y();
1274
drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newTopRight.width() * 2), stableRound(newTopRight.height() * 2));
1278
clipRect.right = centerPoint.x();
1279
clipRect.top = centerPoint.y();
1281
drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomLeft.width() * 2), stableRound(newBottomLeft.height() * 2));
1283
// Draw bottom right
1285
clipRect.left = centerPoint.x();
1286
clipRect.top = centerPoint.y();
1288
drawRoundCorner(needsNewClip, clipRect, rectWin, dc, stableRound(newBottomRight.width() * 2), stableRound(newBottomRight.height() * 2));
1290
SelectObject(dc, oldBrush);
1294
void GraphicsContext::drawRoundCorner(bool needsNewClip, RECT clipRect, RECT rectWin, HDC dc, int width, int height)
1299
OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
1301
clipRgn = adoptPtr(CreateRectRgn(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom));
1302
SelectClipRgn(dc, clipRgn.get());
1304
IntersectClipRect(dc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
1306
::RoundRect(dc, rectWin.left , rectWin.top , rectWin.right , rectWin.bottom , width, height);
1308
SelectClipRgn(dc, needsNewClip ? 0 : clipRgn.get());
1312
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode)
1318
Color gradientAverageColor(const Gradient* gradient)
1320
const Vector<Gradient::ColorStop>& stops = gradient->getStops();
1321
if (stops.isEmpty())
1324
const Gradient::ColorStop& stop = stops.first();
1325
if (stops.size() == 1)
1326
return Color(stop.red, stop.green, stop.blue, stop.alpha);
1328
const Gradient::ColorStop& lastStop = stops.last();
1329
return Color((stop.red + lastStop.red) * 0.5f
1330
, (stop.green + lastStop.green) * 0.5f
1331
, (stop.blue + lastStop.blue) * 0.5f
1332
, (stop.alpha + lastStop.alpha) * 0.5f);
1335
void GraphicsContext::fillPath(const Path& path)
1340
Color c = m_state.fillGradient
1341
? gradientAverageColor(m_state.fillGradient.get())
1344
if (!c.alpha() || !m_data->m_opacity)
1347
ScopeDCProvider dcProvider(m_data);
1351
OwnPtr<HBRUSH> brush = createBrush(c);
1353
if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
1354
IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
1356
TransparentLayerDC transparentDC(m_data, trRect);
1357
HDC dc = transparentDC.hdc();
1361
AffineTransform tr = m_data->m_transform;
1362
tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
1364
SelectObject(dc, GetStockObject(NULL_PEN));
1365
HGDIOBJ oldBrush = SelectObject(dc, brush.get());
1366
path.platformPath()->fillPath(dc, &tr);
1367
SelectObject(dc, oldBrush);
1369
SelectObject(m_data->m_dc, GetStockObject(NULL_PEN));
1370
HGDIOBJ oldBrush = SelectObject(m_data->m_dc, brush.get());
1371
path.platformPath()->fillPath(m_data->m_dc, &m_data->m_transform);
1372
SelectObject(m_data->m_dc, oldBrush);
1377
void GraphicsContext::strokePath(const Path& path)
1379
if (path.isNull() || !m_data->m_opacity)
1382
ScopeDCProvider dcProvider(m_data);
1386
OwnPtr<HPEN> pen = createPen(strokeColor(), strokeThickness(), strokeStyle());
1388
if (m_data->m_opacity < 1.0f || m_data->hasAlpha()) {
1389
IntRect trRect = enclosingIntRect(m_data->mapRect(path.boundingRect()));
1391
TransparentLayerDC transparentDC(m_data, trRect);
1392
HDC dc = transparentDC.hdc();
1396
AffineTransform tr = m_data->m_transform;
1397
tr.translate(transparentDC.toShift().width(), transparentDC.toShift().height());
1399
SelectObject(dc, GetStockObject(NULL_BRUSH));
1400
HGDIOBJ oldPen = SelectObject(dc, pen.get());
1401
path.platformPath()->strokePath(dc, &tr);
1402
SelectObject(dc, oldPen);
1404
SelectObject(m_data->m_dc, GetStockObject(NULL_BRUSH));
1405
HGDIOBJ oldPen = SelectObject(m_data->m_dc, pen.get());
1406
path.platformPath()->strokePath(m_data->m_dc, &m_data->m_transform);
1407
SelectObject(m_data->m_dc, oldPen);
1411
void GraphicsContext::fillRect(const FloatRect& r, const Gradient* gradient)
1413
if (!m_data->m_opacity)
1416
const Vector<Gradient::ColorStop>& stops = gradient->getStops();
1417
if (stops.isEmpty())
1420
size_t numStops = stops.size();
1421
if (numStops == 1) {
1422
const Gradient::ColorStop& stop = stops.first();
1423
Color color(stop.red, stop.green, stop.blue, stop.alpha);
1424
fillRect(r, color, ColorSpaceDeviceRGB);
1428
ScopeDCProvider dcProvider(m_data);
1432
IntRect intRect = enclosingIntRect(r);
1433
IntRect rect = m_data->mapRect(intRect);
1434
TransparentLayerDC transparentDC(m_data, rect, &intRect, 255, true);
1435
HDC dc = transparentDC.hdc();
1439
rect.move(transparentDC.toShift());
1440
FloatPoint fp0 = m_data->mapPoint(gradient->p0());
1441
FloatPoint fp1 = m_data->mapPoint(gradient->p1());
1442
IntPoint p0(stableRound(fp0.x()), stableRound(fp0.y()));
1443
IntPoint p1(stableRound(fp1.x()), stableRound(fp1.y()));
1444
p0 += transparentDC.toShift();
1445
p1 += transparentDC.toShift();
1447
if (gradient->isRadial()) {
1448
if (g_radialGradientFiller) {
1449
// FIXME: don't support 2D scaling at this time
1450
double scale = (m_data->m_transform.a() + m_data->m_transform.d()) * 0.5;
1451
float r0 = gradient->startRadius() * scale;
1452
float r1 = gradient->endRadius() * scale;
1453
g_radialGradientFiller(dc, rect, p0, p1, r0, r1, gradient->getStops());
1456
} else if (g_linearGradientFiller) {
1457
g_linearGradientFiller(dc, rect, p0, p1, gradient->getStops());
1461
// Simple 1D linear solution that assumes p0 is on the top or left side, and p1 is on the right or bottom side
1462
size_t numRects = (numStops - 1);
1463
Vector<TRIVERTEX, 20> tv;
1464
tv.resize(numRects * 2);
1465
Vector<GRADIENT_RECT, 10> mesh;
1466
mesh.resize(numRects);
1469
int width = rect.width();
1470
int height = rect.height();
1471
FloatSize d = gradient->p1() - gradient->p0();
1472
bool vertical = fabs(d.height()) > fabs(d.width());
1473
for (size_t i = 0; i < numStops; ++i) {
1474
const Gradient::ColorStop& stop = stops[i];
1475
int iTv = i ? 2 * i - 1 : 0;
1476
tv[iTv].Red = stop.red * 0xFFFF;
1477
tv[iTv].Green = stop.green * 0xFFFF;
1478
tv[iTv].Blue = stop.blue * 0xFFFF;
1479
tv[iTv].Alpha = stop.alpha * 0xFFFF;
1481
tv[iTv].x = vertical ? x + width: x + width * stop.stop;
1482
tv[iTv].y = vertical ? y + height * stop.stop : y + height;
1483
mesh[i - 1].UpperLeft = iTv - 1;
1484
mesh[i - 1].LowerRight = iTv;
1490
if (i && i < numRects) {
1491
tv[iTv + 1] = tv[iTv];
1499
GradientFill(dc, tv.data(), tv.size(), mesh.data(), mesh.size(), vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
1502
AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const
1504
if (paintingDisabled())
1505
return AffineTransform();
1507
return m_data->m_transform;
1510
void GraphicsContext::fillRect(const FloatRect& rect)
1512
savePlatformState();
1514
if (m_state.fillGradient)
1515
fillRect(rect, m_state.fillGradient.get());
1517
fillRect(rect, fillColor(), ColorSpaceDeviceRGB);
1519
restorePlatformState();
1522
void GraphicsContext::setPlatformShadow(const FloatSize&, float, const Color&, ColorSpace)
1527
void GraphicsContext::clearPlatformShadow()
1532
InterpolationQuality GraphicsContext::imageInterpolationQuality() const
1535
return InterpolationDefault;
1538
void GraphicsContext::setImageInterpolationQuality(InterpolationQuality)
1543
static inline bool isCharVisible(UChar c)
1545
return c && c != zeroWidthSpace;
1548
void GraphicsContext::drawText(const Font& font, const TextRun& run, const FloatPoint& point, int from, int to)
1550
if (paintingDisabled() || !fillColor().alpha() || !m_data->m_opacity)
1553
bool mustSupportAlpha = m_data->hasAlpha();
1555
if (!mustSupportAlpha && fillColor().alpha() == 0xFF && m_data->m_opacity >= 1.0) {
1556
font.drawText(this, run, point, from, to);
1560
float oldOpacity = m_data->m_opacity;
1561
m_data->m_opacity *= fillColor().alpha() / 255.0;
1563
FloatRect textRect = font.selectionRectForText(run, point, font.fontMetrics().height(), from, to);
1564
textRect.setY(textRect.y() - font.fontMetrics().ascent());
1565
IntRect trRect = enclosingIntRect(m_data->mapRect(textRect));
1567
AlphaPaintType alphaPaintType = mustSupportAlpha ? AlphaPaintOther : AlphaPaintNone;
1568
if (RefPtr<SharedBitmap> bmp = m_data->getTransparentLayerBitmap(trRect, alphaPaintType, bmpRect, true, mustSupportAlpha)) {
1570
GraphicsContext gc(0);
1572
gc.scale(FloatSize(m_data->m_transform.a(), m_data->m_transform.d()));
1573
font.drawText(&gc, run, IntPoint(0, font.fontMetrics().ascent()), from, to);
1576
HDC memDC = bmp->getDC(&key1);
1578
m_data->paintBackTransparentLayerBitmap(memDC, bmp.get(), trRect, alphaPaintType, bmpRect);
1579
bmp->releaseDC(memDC, key1);
1583
m_data->m_opacity = oldOpacity;
1586
void GraphicsContext::drawText(const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer,
1587
int from, int numGlyphs, const FloatPoint& point)
1589
if (!m_data->m_opacity)
1595
if (isCharVisible(*glyphBuffer.glyphs(from)))
1601
double scaleX = m_data->m_transform.a();
1602
double scaleY = m_data->m_transform.d();
1604
int height = fontData->platformData().size() * scaleY;
1605
int width = fontData->avgCharWidth() * scaleX;
1607
if (!height || !width)
1610
ScopeDCProvider dcProvider(m_data);
1614
HFONT hFont = height > 1
1615
? fontData->platformData().getScaledFontHandle(height, scaleX == scaleY ? 0 : width)
1618
FloatPoint startPoint(point.x(), point.y() - fontData->fontMetrics().ascent());
1619
FloatPoint trPoint = m_data->mapPoint(startPoint);
1620
int y = stableRound(trPoint.y());
1622
Color color = fillColor();
1626
COLORREF fontColor = RGB(color.red(), color.green(), color.blue());
1629
double offset = trPoint.x();
1630
const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
1632
for (int i = 1; i < numGlyphs; ++i)
1633
offset += (*advance++).width();
1635
for (int i = 1; i < numGlyphs; ++i)
1636
offset += (*advance++).width() * scaleX;
1640
OwnPtr<HPEN> hPen = adoptPtr(CreatePen(PS_DASH, 1, fontColor));
1641
HGDIOBJ oldPen = SelectObject(m_data->m_dc, hPen.get());
1643
MoveToEx(m_data->m_dc, stableRound(trPoint.x()), y, 0);
1644
LineTo(m_data->m_dc, stableRound(offset), y);
1646
SelectObject(m_data->m_dc, oldPen);
1650
FloatSize shadowOffset;
1651
float shadowBlur = 0;
1653
ColorSpace shadowColorSpace;
1654
bool hasShadow = textDrawingMode() == TextModeFill
1655
&& getShadow(shadowOffset, shadowBlur, shadowColor, shadowColorSpace)
1656
&& shadowColor.alpha();
1657
COLORREF shadowRGBColor;
1658
FloatPoint trShadowPoint;
1660
shadowRGBColor = RGB(shadowColor.red(), shadowColor.green(), shadowColor.blue());
1661
trShadowPoint = m_data->mapPoint(startPoint + shadowOffset);
1664
HGDIOBJ hOldFont = SelectObject(m_data->m_dc, hFont);
1665
COLORREF oldTextColor = GetTextColor(m_data->m_dc);
1666
int oldTextAlign = GetTextAlign(m_data->m_dc);
1667
SetTextAlign(m_data->m_dc, 0);
1669
int oldBkMode = GetBkMode(m_data->m_dc);
1670
SetBkMode(m_data->m_dc, TRANSPARENT);
1672
if (numGlyphs > 1) {
1673
double offset = trPoint.x();
1674
Vector<int, 256> glyphSpace(numGlyphs);
1675
Vector<UChar, 256> text(numGlyphs);
1676
int* curSpace = glyphSpace.data();
1677
UChar* curChar = text.data();
1678
const UChar* srcChar = glyphBuffer.glyphs(from);
1679
const UChar* const srcCharEnd = srcChar + numGlyphs;
1680
*curChar++ = *srcChar++;
1681
int firstOffset = stableRound(offset);
1682
int lastOffset = firstOffset;
1683
const GlyphBufferAdvance* advance = glyphBuffer.advances(from);
1684
// FIXME: ExtTextOut() can flip over each word for RTL languages, even when TA_RTLREADING is off.
1685
// (this can be GDI bug or font driver bug?)
1686
// We are not clear how it processes characters and handles specified spaces. On the other side,
1687
// our glyph buffer is already in the correct order for rendering. So, the solution is that we
1688
// call ExtTextOut() for each single character when the text contains any RTL character.
1689
// This solution is not perfect as it is slower than calling ExtTextOut() one time for all characters.
1690
// Drawing characters one by one may be too slow.
1691
bool drawOneByOne = false;
1693
for (; srcChar < srcCharEnd; ++srcChar) {
1694
offset += (*advance++).width();
1695
int offsetInt = stableRound(offset);
1696
if (isCharVisible(*srcChar)) {
1697
if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
1698
drawOneByOne = true;
1699
*curChar++ = *srcChar;
1700
*curSpace++ = offsetInt - lastOffset;
1701
lastOffset = offsetInt;
1705
for (; srcChar < srcCharEnd; ++srcChar) {
1706
offset += (*advance++).width() * scaleX;
1707
int offsetInt = stableRound(offset);
1708
if (isCharVisible(*srcChar)) {
1709
if (!drawOneByOne && WTF::Unicode::direction(*srcChar) == WTF::Unicode::RightToLeft)
1710
drawOneByOne = true;
1711
*curChar++ = *srcChar;
1712
*curSpace++ = offsetInt - lastOffset;
1713
lastOffset = offsetInt;
1717
numGlyphs = curChar - text.data();
1719
SetTextColor(m_data->m_dc, shadowRGBColor);
1721
int xShadow = firstOffset + stableRound(trShadowPoint.x() - trPoint.x());
1722
int yShadow = stableRound(trShadowPoint.y());
1723
for (int i = 0; i < numGlyphs; ++i) {
1724
ExtTextOut(m_data->m_dc, xShadow, yShadow, 0, NULL, text.data() + i, 1, 0);
1725
xShadow += glyphSpace[i];
1728
ExtTextOut(m_data->m_dc, firstOffset + stableRound(trShadowPoint.x() - trPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, text.data(), numGlyphs, glyphSpace.data());
1730
SetTextColor(m_data->m_dc, fontColor);
1732
int x = firstOffset;
1733
for (int i = 0; i < numGlyphs; ++i) {
1734
ExtTextOut(m_data->m_dc, x, y, 0, NULL, text.data() + i, 1, 0);
1738
ExtTextOut(m_data->m_dc, firstOffset, y, 0, NULL, text.data(), numGlyphs, glyphSpace.data());
1740
UChar c = *glyphBuffer.glyphs(from);
1742
SetTextColor(m_data->m_dc, shadowRGBColor);
1743
ExtTextOut(m_data->m_dc, stableRound(trShadowPoint.x()), stableRound(trShadowPoint.y()), 0, NULL, &c, 1, 0);
1745
SetTextColor(m_data->m_dc, fontColor);
1746
ExtTextOut(m_data->m_dc, stableRound(trPoint.x()), y, 0, NULL, &c, 1, 0);
1749
SetTextAlign(m_data->m_dc, oldTextAlign);
1750
SetTextColor(m_data->m_dc, oldTextColor);
1751
SetBkMode(m_data->m_dc, oldBkMode);
1752
SelectObject(m_data->m_dc, hOldFont);
1755
void GraphicsContext::drawFrameControl(const IntRect& rect, unsigned type, unsigned state)
1757
if (!m_data->m_opacity)
1760
const int boxWidthBest = 8;
1761
const int boxHeightBest = 8;
1763
ScopeDCProvider dcProvider(m_data);
1767
IntRect trRect = m_data->mapRect(rect);
1768
TransparentLayerDC transparentDC(m_data, trRect, &rect, 255, true);
1769
HDC dc = transparentDC.hdc();
1772
trRect.move(transparentDC.toShift());
1774
RECT rectWin = trRect;
1776
if ((rectWin.right - rectWin.left) < boxWidthBest) {
1777
RefPtr<SharedBitmap> bmp = SharedBitmap::create(IntSize(boxWidthBest, boxHeightBest), BitmapInfo::BitCount16, true);
1778
SharedBitmap::DCHolder memDC(bmp.get());
1780
RECT tempRect = {0, 0, boxWidthBest, boxHeightBest};
1781
DrawFrameControl(memDC.get(), &tempRect, type, state);
1783
::StretchBlt(dc, rectWin.left, rectWin.top, rectWin.right - rectWin.left, rectWin.bottom - rectWin.top, memDC.get(), 0, 0, boxWidthBest, boxHeightBest, SRCCOPY);
1788
DrawFrameControl(dc, &rectWin, type, state);
1791
void GraphicsContext::drawFocusRect(const IntRect& rect)
1793
if (!m_data->m_opacity)
1796
ScopeDCProvider dcProvider(m_data);
1800
IntRect trRect = m_data->mapRect(rect);
1801
TransparentLayerDC transparentDC(m_data, trRect, &rect);
1802
HDC dc = transparentDC.hdc();
1805
trRect.move(transparentDC.toShift());
1807
RECT rectWin = trRect;
1808
DrawFocusRect(dc, &rectWin);
1811
void GraphicsContext::paintTextField(const IntRect& rect, unsigned state)
1813
if (!m_data->m_opacity)
1816
ScopeDCProvider dcProvider(m_data);
1820
IntRect trRect = m_data->mapRect(rect);
1821
TransparentLayerDC transparentDC(m_data, trRect, &rect);
1822
HDC dc = transparentDC.hdc();
1825
trRect.move(transparentDC.toShift());
1827
RECT rectWin = trRect;
1828
DrawEdge(dc, &rectWin, EDGE_ETCHED, BF_RECT | BF_ADJUST);
1829
FillRect(dc, &rectWin, reinterpret_cast<HBRUSH>(((state & DFCS_INACTIVE) ? COLOR_BTNFACE : COLOR_WINDOW) + 1));
1832
void GraphicsContext::drawBitmap(SharedBitmap* bmp, const IntRect& dstRectIn, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
1834
if (!m_data->m_opacity)
1837
ScopeDCProvider dcProvider(m_data);
1841
IntRect dstRect = m_data->mapRect(dstRectIn);
1842
TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
1843
HDC dc = transparentDC.hdc();
1846
dstRect.move(transparentDC.toShift());
1848
bmp->draw(dc, dstRect, srcRect, compositeOp);
1851
transparentDC.fillAlphaChannel();
1854
void GraphicsContext::drawBitmapPattern(SharedBitmap* bmp, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
1855
const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRectIn, const IntSize& origSourceSize)
1857
if (!m_data->m_opacity)
1860
ScopeDCProvider dcProvider(m_data);
1864
IntRect intDstRect = enclosingIntRect(destRectIn);
1865
IntRect trRect = m_data->mapRect(intDstRect);
1866
TransparentLayerDC transparentDC(m_data, trRect, &intDstRect, 255, true);
1867
HDC dc = transparentDC.hdc();
1870
trRect.move(transparentDC.toShift());
1871
FloatRect movedDstRect = m_data->m_transform.inverse().mapRect(FloatRect(trRect));
1872
FloatSize moved(movedDstRect.location() - destRectIn.location());
1873
AffineTransform transform = m_data->m_transform;
1874
transform.translate(moved.width(), moved.height());
1876
bmp->drawPattern(dc, transform, tileRectIn, patternTransform, phase, styleColorSpace, op, destRectIn, origSourceSize);
1878
if (!bmp->hasAlpha())
1879
transparentDC.fillAlphaChannel();
1882
void GraphicsContext::drawIcon(HICON icon, const IntRect& dstRectIn, UINT flags)
1884
if (!m_data->m_opacity)
1887
ScopeDCProvider dcProvider(m_data);
1891
IntRect dstRect = m_data->mapRect(dstRectIn);
1892
TransparentLayerDC transparentDC(m_data, dstRect, &dstRectIn, 255, true);
1893
HDC dc = transparentDC.hdc();
1896
dstRect.move(transparentDC.toShift());
1898
DrawIconEx(dc, dstRect.x(), dstRect.y(), icon, dstRect.width(), dstRect.height(), 0, NULL, flags);
1901
void GraphicsContext::setPlatformShouldAntialias(bool)
1906
void GraphicsContext::setLineDash(const DashArray&, float)
1911
void GraphicsContext::clipPath(const Path&, WindRule)
1916
} // namespace WebCore