1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/dfb/dc.cpp
3 // Purpose: wxDFBDCImpl class
4 // Author: Vaclav Slavik
6 // Copyright: (c) 2006 REA Elektronik GmbH
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // ===========================================================================
12 // ===========================================================================
14 // ---------------------------------------------------------------------------
16 // ---------------------------------------------------------------------------
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
26 #include "wx/dcmemory.h"
30 #include "wx/dfb/dc.h"
31 #include "wx/dfb/private.h"
33 // these values are used to initialize newly created DC
34 #define DEFAULT_FONT (*wxNORMAL_FONT)
35 #define DEFAULT_PEN (*wxBLACK_PEN)
36 #define DEFAULT_BRUSH (*wxWHITE_BRUSH)
38 // ===========================================================================
40 // ===========================================================================
42 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
46 IMPLEMENT_ABSTRACT_CLASS(wxDFBDCImpl
, wxDCImpl
)
48 void wxDFBDCImpl::DFBInit(const wxIDirectFBSurfacePtr
& surface
)
52 wxCHECK_RET( surface
!= NULL
, "invalid surface" );
54 m_mm_to_pix_x
= (double)wxGetDisplaySize().GetWidth() /
55 (double)wxGetDisplaySizeMM().GetWidth();
56 m_mm_to_pix_y
= (double)wxGetDisplaySize().GetHeight() /
57 (double)wxGetDisplaySizeMM().GetHeight();
59 SetFont(DEFAULT_FONT
);
61 SetBrush(DEFAULT_BRUSH
);
65 // ---------------------------------------------------------------------------
67 // ---------------------------------------------------------------------------
69 void wxDFBDCImpl::DoSetClippingRegion(wxCoord cx
, wxCoord cy
, wxCoord cw
, wxCoord ch
)
71 wxCHECK_RET( IsOk(), wxT("invalid dc") );
73 wxSize
size(GetSize());
75 wxASSERT_MSG( !m_clipping
,
76 "narrowing clipping region not implemented yet" );
78 // NB: We intersect the clipping rectangle with surface's area here because
79 // DirectFB will return an error if you try to set clipping rectangle
80 // that is partially outside of the surface.
82 r
.x1
= wxMax(0, XLOG2DEV(cx
));
83 r
.y1
= wxMax(0, YLOG2DEV(cy
));
84 r
.x2
= wxMin(r
.x1
+ XLOG2DEVREL(cw
), size
.x
) - 1;
85 r
.y2
= wxMin(r
.y1
+ YLOG2DEVREL(ch
), size
.y
) - 1;
87 if ( !m_surface
->SetClip(&r
) )
92 m_clipX2
= cx
+ cw
- 1;
93 m_clipY2
= cy
+ ch
-1;
97 void wxDFBDCImpl::DoSetDeviceClippingRegion(const wxRegion
& region
)
99 // NB: this can be done because wxDFB only supports rectangular regions
100 wxRect rect
= region
.AsRect();
102 // our parameter is in physical coordinates while DoSetClippingRegion()
103 // takes logical ones
104 rect
.x
= XDEV2LOG(rect
.x
);
105 rect
.y
= YDEV2LOG(rect
.y
);
106 rect
.width
= XDEV2LOG(rect
.width
);
107 rect
.height
= YDEV2LOG(rect
.height
);
109 DoSetClippingRegion(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
112 void wxDFBDCImpl::DestroyClippingRegion()
114 wxCHECK_RET( IsOk(), wxT("invalid dc") );
116 m_surface
->SetClip(NULL
);
121 // ---------------------------------------------------------------------------
122 // query capabilities
123 // ---------------------------------------------------------------------------
125 int wxDFBDCImpl::GetDepth() const
127 return m_surface
->GetDepth();
130 // ---------------------------------------------------------------------------
132 // ---------------------------------------------------------------------------
134 void wxDFBDCImpl::Clear()
136 wxCHECK_RET( IsOk(), wxT("invalid dc") );
138 if ( m_backgroundBrush
.GetStyle() == wxTRANSPARENT
)
141 wxColour clr
= m_backgroundBrush
.GetColour();
142 m_surface
->Clear(clr
.Red(), clr
.Green(), clr
.Blue(), clr
.Alpha());
144 wxSize
size(GetSize());
145 CalcBoundingBox(XDEV2LOG(0), YDEV2LOG(0));
146 CalcBoundingBox(XDEV2LOG(size
.x
), YDEV2LOG(size
.y
));
149 extern bool wxDoFloodFill(wxDC
*dc
, wxCoord x
, wxCoord y
,
150 const wxColour
& col
, wxFloodFillStyle style
);
152 bool wxDFBDCImpl::DoFloodFill(wxCoord x
, wxCoord y
,
153 const wxColour
& col
, wxFloodFillStyle style
)
155 return wxDoFloodFill(GetOwner(), x
, y
, col
, style
);
158 bool wxDFBDCImpl::DoGetPixel(wxCoord x
, wxCoord y
, wxColour
*col
) const
160 wxCHECK_MSG( col
, false, "NULL colour parameter in wxDFBDCImpl::GetPixel");
162 wxFAIL_MSG( "GetPixel not implemented" );
170 void wxDFBDCImpl::DoCrossHair(wxCoord x
, wxCoord y
)
172 wxCHECK_RET( IsOk(), wxT("invalid dc") );
174 wxFAIL_MSG( "CrossHair not implemented" );
180 void wxDFBDCImpl::DoDrawLine(wxCoord x1
, wxCoord y1
, wxCoord x2
, wxCoord y2
)
182 wxCHECK_RET( IsOk(), wxT("invalid dc") );
184 if ( m_pen
.GetStyle() == wxTRANSPARENT
)
187 wxCoord xx1
= XLOG2DEV(x1
);
188 wxCoord yy1
= YLOG2DEV(y1
);
189 wxCoord xx2
= XLOG2DEV(x2
);
190 wxCoord yy2
= YLOG2DEV(y2
);
192 // FIXME: DrawLine() shouldn't draw the last pixel, but DFB's DrawLine()
193 // does draw it. We should undo any change to the last pixel by
194 // using GetPixel() and PutPixel(), but until they are implemented,
195 // handle at least the special case of vertical and horizontal
201 else if ( yy1
> yy2
)
208 else if ( xx1
> xx2
)
212 m_surface
->DrawLine(xx1
, yy1
, xx2
, yy2
);
214 CalcBoundingBox(x1
, y1
);
215 CalcBoundingBox(x2
, y2
);
218 // Draws an arc of a circle, centred on (xc, yc), with starting point (x1, y1)
219 // and ending at (x2, y2)
220 void wxDFBDCImpl::DoDrawArc(wxCoord
WXUNUSED(x1
), wxCoord
WXUNUSED(y1
),
221 wxCoord
WXUNUSED(x2
), wxCoord
WXUNUSED(y2
),
222 wxCoord
WXUNUSED(xc
), wxCoord
WXUNUSED(yc
))
224 wxCHECK_RET( IsOk(), wxT("invalid dc") );
226 wxFAIL_MSG( "DrawArc not implemented" );
229 void wxDFBDCImpl::DoDrawPoint(wxCoord x
, wxCoord y
)
231 wxCHECK_RET( IsOk(), wxT("invalid dc") );
233 // NB: DirectFB API doesn't provide a function for drawing points, so
234 // implement it as 1px long line. This is inefficient, but then, so is
235 // using DrawPoint() for drawing more than a few points.
236 DoDrawLine(x
, y
, x
, y
);
238 // FIXME_DFB: implement special cases for common formats (RGB24,RGBA/RGB32)
241 void wxDFBDCImpl::DoDrawPolygon(int WXUNUSED(n
), const wxPoint
WXUNUSED(points
)[],
242 wxCoord
WXUNUSED(xoffset
), wxCoord
WXUNUSED(yoffset
),
243 wxPolygonFillMode
WXUNUSED(fillStyle
))
245 wxCHECK_RET( IsOk(), wxT("invalid dc") );
247 wxFAIL_MSG( "DrawPolygon not implemented" );
250 void wxDFBDCImpl::DoDrawLines(int WXUNUSED(n
), const wxPoint
WXUNUSED(points
)[],
251 wxCoord
WXUNUSED(xoffset
), wxCoord
WXUNUSED(yoffset
))
253 wxCHECK_RET( IsOk(), wxT("invalid dc") );
255 // TODO: impl. using DirectDB's DrawLines
256 wxFAIL_MSG( "DrawLines not implemented" );
259 void wxDFBDCImpl::DoDrawRectangle(wxCoord x
, wxCoord y
, wxCoord width
, wxCoord height
)
261 wxCHECK_RET( IsOk(), wxT("invalid dc") );
263 wxCoord xx
= XLOG2DEV(x
);
264 wxCoord yy
= YLOG2DEV(y
);
265 wxCoord ww
= m_signX
* XLOG2DEVREL(width
);
266 wxCoord hh
= m_signY
* YLOG2DEVREL(height
);
268 if ( ww
== 0 || hh
== 0 ) return;
281 if ( m_brush
.GetStyle() != wxTRANSPARENT
)
283 SelectColour(m_brush
.GetColour());
284 m_surface
->FillRectangle(xx
, yy
, ww
, hh
);
285 // restore pen's colour, because other drawing functions expect the
286 // colour to be set to the pen:
287 SelectColour(m_pen
.GetColour());
290 if ( m_pen
.GetStyle() != wxTRANSPARENT
)
292 m_surface
->DrawRectangle(xx
, yy
, ww
, hh
);
295 CalcBoundingBox(x
, y
);
296 CalcBoundingBox(x
+ width
, y
+ height
);
299 void wxDFBDCImpl::DoDrawRoundedRectangle(wxCoord
WXUNUSED(x
),
301 wxCoord
WXUNUSED(width
),
302 wxCoord
WXUNUSED(height
),
303 double WXUNUSED(radius
))
305 wxCHECK_RET( IsOk(), wxT("invalid dc") );
307 wxFAIL_MSG( "DrawRoundedRectangle not implemented" );
310 void wxDFBDCImpl::DoDrawEllipse(wxCoord
WXUNUSED(x
),
312 wxCoord
WXUNUSED(width
),
313 wxCoord
WXUNUSED(height
))
315 wxCHECK_RET( IsOk(), wxT("invalid dc") );
317 wxFAIL_MSG( "DrawElipse not implemented" );
320 void wxDFBDCImpl::DoDrawEllipticArc(wxCoord
WXUNUSED(x
),
327 wxCHECK_RET( IsOk(), wxT("invalid dc") );
329 wxFAIL_MSG( "DrawElipticArc not implemented" );
332 void wxDFBDCImpl::DoDrawText(const wxString
& text
, wxCoord x
, wxCoord y
)
334 wxCHECK_RET( IsOk(), wxT("invalid dc") );
336 wxCoord xx
= XLOG2DEV(x
);
337 wxCoord yy
= YLOG2DEV(y
);
339 // update the bounding box
341 CalcBoundingBox(x
, y
);
342 DoGetTextExtent(text
, &w
, &h
);
343 CalcBoundingBox(x
+ w
, y
+ h
);
345 // if background mode is solid, DrawText must paint text's background:
346 if ( m_backgroundMode
== wxSOLID
)
348 wxCHECK_RET( m_textBackgroundColour
.IsOk(),
349 wxT("invalid background color") );
351 SelectColour(m_textBackgroundColour
);
352 m_surface
->FillRectangle(xx
, yy
, XLOG2DEVREL(w
), YLOG2DEVREL(h
));
355 // finally draw the text itself:
356 wxCHECK_RET( m_textForegroundColour
.IsOk(),
357 wxT("invalid foreground color") );
358 SelectColour(m_textForegroundColour
);
359 m_surface
->DrawString(text
.utf8_str(), -1, xx
, yy
, DSTF_LEFT
| DSTF_TOP
);
361 // restore pen's colour, because other drawing functions expect the colour
362 // to be set to the pen:
363 SelectColour(m_pen
.GetColour());
366 void wxDFBDCImpl::DoDrawRotatedText(const wxString
& WXUNUSED(text
),
367 wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
),
368 double WXUNUSED(angle
))
370 wxCHECK_RET( IsOk(), wxT("invalid dc") );
372 wxFAIL_MSG( "DrawRotatedText not implemented" );
375 // ---------------------------------------------------------------------------
377 // ---------------------------------------------------------------------------
379 void wxDFBDCImpl::SetPen(const wxPen
& pen
)
381 m_pen
= pen
.IsOk() ? pen
: DEFAULT_PEN
;
383 SelectColour(m_pen
.GetColour());
386 void wxDFBDCImpl::SetBrush(const wxBrush
& brush
)
388 m_brush
= brush
.IsOk() ? brush
: DEFAULT_BRUSH
;
391 void wxDFBDCImpl::SelectColour(const wxColour
& clr
)
393 m_surface
->SetColor(clr
.Red(), clr
.Green(), clr
.Blue(), clr
.Alpha());
394 #warning "use SetColorIndex?"
398 void wxDFBDCImpl::SetPalette(const wxPalette
& WXUNUSED(palette
))
400 wxCHECK_RET( IsOk(), wxT("invalid dc") );
402 wxFAIL_MSG( "SetPalette not implemented" );
404 #endif // wxUSE_PALETTE
406 void wxDFBDCImpl::SetFont(const wxFont
& font
)
408 wxCHECK_RET( IsOk(), wxT("invalid dc") );
410 wxFont
f(font
.IsOk() ? font
: DEFAULT_FONT
);
412 wxFont
oldfont(m_font
);
416 if ( !m_surface
->SetFont(GetCurrentFont()) )
423 wxIDirectFBFontPtr
wxDFBDCImpl::GetCurrentFont() const
425 bool aa
= (GetDepth() > 8);
426 return m_font
.GetDirectFBFont(aa
);
429 void wxDFBDCImpl::SetBackground(const wxBrush
& brush
)
431 wxCHECK_RET( IsOk(), wxT("invalid dc") );
433 if (!brush
.IsOk()) return;
435 m_backgroundBrush
= brush
;
438 void wxDFBDCImpl::SetBackgroundMode(int mode
)
440 m_backgroundMode
= mode
;
443 void wxDFBDCImpl::SetLogicalFunction(wxRasterOperationMode function
)
445 wxCHECK_RET( IsOk(), wxT("invalid dc") );
447 // NB: we could also support XOR, but for blitting only (via DSBLIT_XOR);
448 // and possibly others via SetSrc/DstBlendFunction()
449 wxASSERT_MSG( function
== wxCOPY
,
450 "only wxCOPY logical function supported" );
452 m_logicalFunction
= function
;
455 bool wxDFBDCImpl::StartDoc(const wxString
& WXUNUSED(message
))
457 // We might be previewing, so return true to let it continue.
461 void wxDFBDCImpl::EndDoc()
465 void wxDFBDCImpl::StartPage()
469 void wxDFBDCImpl::EndPage()
473 // ---------------------------------------------------------------------------
475 // ---------------------------------------------------------------------------
477 wxCoord
wxDFBDCImpl::GetCharHeight() const
479 wxCHECK_MSG( IsOk(), -1, wxT("invalid dc") );
480 wxCHECK_MSG( m_font
.IsOk(), -1, wxT("no font selected") );
483 GetCurrentFont()->GetHeight(&h
);
484 return YDEV2LOGREL(h
);
487 wxCoord
wxDFBDCImpl::GetCharWidth() const
489 wxCHECK_MSG( IsOk(), -1, wxT("invalid dc") );
490 wxCHECK_MSG( m_font
.IsOk(), -1, wxT("no font selected") );
493 GetCurrentFont()->GetStringWidth("H", 1, &w
);
494 // VS: YDEV is corrent, it should *not* be XDEV, because font's are only
495 // scaled according to m_scaleY
496 return YDEV2LOGREL(w
);
499 void wxDFBDCImpl::DoGetTextExtent(const wxString
& string
, wxCoord
*x
, wxCoord
*y
,
500 wxCoord
*descent
, wxCoord
*externalLeading
,
501 const wxFont
*theFont
) const
503 wxCHECK_RET( IsOk(), wxT("invalid dc") );
504 wxCHECK_RET( m_font
.IsOk(), wxT("no font selected") );
505 wxCHECK_RET( !theFont
|| theFont
->IsOk(), wxT("invalid font") );
508 if ( theFont
!= NULL
)
511 wxConstCast(this, wxDFBDCImpl
)->SetFont(*theFont
);
514 wxCoord xx
= 0, yy
= 0;
516 wxIDirectFBFontPtr f
= GetCurrentFont();
518 if ( f
->GetStringExtents(string
.utf8_str(), -1, &rect
, NULL
) )
520 // VS: YDEV is corrent, it should *not* be XDEV, because font's are
521 // only scaled according to m_scaleY
522 xx
= YDEV2LOGREL(rect
.w
);
523 yy
= YDEV2LOGREL(rect
.h
);
528 if ( f
->GetDescender(&d
) )
529 *descent
= YDEV2LOGREL(-d
);
537 if ( externalLeading
) *externalLeading
= 0;
539 if ( theFont
!= NULL
)
540 wxConstCast(this, wxDFBDCImpl
)->SetFont(oldFont
);
545 // ---------------------------------------------------------------------------
547 // ---------------------------------------------------------------------------
549 // FIXME_DFB: scaling affects pixel size of font, pens, brushes, which
550 // is not currently implemented here; probably makes sense to
551 // switch to Cairo instead of implementing everything for DFB
553 void wxDFBDCImpl::DoGetSize(int *w
, int *h
) const
555 wxCHECK_RET( IsOk(), wxT("invalid dc") );
557 m_surface
->GetSize(w
, h
);
560 void wxDFBDCImpl::DoGetSizeMM(int *width
, int *height
) const
562 #warning "move this to common code?"
566 if ( width
) *width
= int(double(w
) / (m_userScaleX
*m_mm_to_pix_x
));
567 if ( height
) *height
= int(double(h
) / (m_userScaleY
*m_mm_to_pix_y
));
570 wxSize
wxDFBDCImpl::GetPPI() const
572 #warning "move this to common code?"
573 return wxSize(int(double(m_mm_to_pix_x
) * inches2mm
),
574 int(double(m_mm_to_pix_y
) * inches2mm
));
578 // ---------------------------------------------------------------------------
580 // ---------------------------------------------------------------------------
582 bool wxDFBDCImpl::DoBlit(wxCoord xdest
, wxCoord ydest
,
583 wxCoord width
, wxCoord height
,
584 wxDC
*source
, wxCoord xsrc
, wxCoord ysrc
,
585 wxRasterOperationMode rop
, bool useMask
,
586 wxCoord xsrcMask
, wxCoord ysrcMask
)
588 wxCHECK_MSG( IsOk(), false, "invalid dc" );
589 wxCHECK_MSG( source
, false, "invalid source dc" );
591 // NB: we could also support XOR here (via DSBLIT_XOR)
592 // and possibly others via SetSrc/DstBlendFunction()
593 wxCHECK_MSG( rop
== wxCOPY
, false, "only wxCOPY function supported" );
595 // transform the source DC coords to the device ones
596 xsrc
= source
->LogicalToDeviceX(xsrc
);
597 ysrc
= source
->LogicalToDeviceY(ysrc
);
599 // FIXME_DFB: use the mask origin when drawing transparently
600 wxASSERT_MSG( xsrcMask
== -1 && ysrcMask
== -1,
601 "non-default source mask offset not implemented" );
603 if (xsrcMask
== -1 && ysrcMask
== -1)
605 xsrcMask
= xsrc
; ysrcMask
= ysrc
;
609 xsrcMask
= source
->LogicalToDeviceX(xsrcMask
);
610 ysrcMask
= source
->LogicalToDeviceY(ysrcMask
);
614 wxMemoryDC
*sourceAsMemDC
= wxDynamicCast(source
, wxMemoryDC
);
617 DoDrawSubBitmap(sourceAsMemDC
->GetSelectedBitmap(),
626 return DoBlitFromSurface
628 static_cast<wxDFBDCImpl
*>(source
->GetImpl())
629 ->GetDirectFBSurface(),
639 void wxDFBDCImpl::DoDrawBitmap(const wxBitmap
&bmp
, wxCoord x
, wxCoord y
, bool useMask
)
641 wxCHECK_RET( IsOk(), wxT("invalid dc") );
642 wxCHECK_RET( bmp
.IsOk(), wxT("invalid bitmap") );
645 0, 0, bmp
.GetWidth(), bmp
.GetHeight(),
647 m_logicalFunction
, useMask
);
650 void wxDFBDCImpl::DoDrawIcon(const wxIcon
& icon
, wxCoord x
, wxCoord y
)
652 // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why
653 DoDrawBitmap((const wxBitmap
&)icon
, x
, y
, true);
656 void wxDFBDCImpl::DoDrawSubBitmap(const wxBitmap
&bmp
,
657 wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
,
658 wxCoord destx
, wxCoord desty
, int rop
, bool useMask
)
660 wxCHECK_RET( IsOk(), wxT("invalid dc") );
661 wxCHECK_RET( bmp
.IsOk(), wxT("invalid bitmap") );
663 // NB: we could also support XOR here (via DSBLIT_XOR)
664 // and possibly others via SetSrc/DstBlendFunction()
665 wxCHECK_RET( rop
== wxCOPY
, "only wxCOPY function supported" );
667 if ( bmp
.GetDepth() == 1 )
669 // Mono bitmaps are handled in special way -- all 1s are drawn in
670 // foreground colours, all 0s in background colour.
671 wxFAIL_MSG( "drawing mono bitmaps not implemented" );
675 if ( useMask
&& bmp
.GetMask() )
677 // FIXME_DFB: Could use blitting modes for this; also see
678 // DFB's SetSrcBlendFunction() and SetSrcColorKey()
679 wxFAIL_MSG( "drawing bitmaps with masks not implemented" );
683 DoBlitFromSurface(bmp
.GetDirectFBSurface(),
689 bool wxDFBDCImpl::DoBlitFromSurface(const wxIDirectFBSurfacePtr
& src
,
690 wxCoord srcx
, wxCoord srcy
,
691 wxCoord w
, wxCoord h
,
692 wxCoord dstx
, wxCoord dsty
)
694 // don't do anything if the source rectangle is outside of source surface,
695 // DirectFB would assert in that case:
697 src
->GetSize(&srcsize
.x
, &srcsize
.y
);
698 if ( !wxRect(srcx
, srcy
, w
, h
).Intersects(wxRect(srcsize
)) )
700 wxLogDebug("Blitting from area outside of the source surface, caller code needs fixing.");
704 CalcBoundingBox(dstx
, dsty
);
705 CalcBoundingBox(dstx
+ w
, dsty
+ h
);
707 DFBRectangle srcRect
= { srcx
, srcy
, w
, h
};
708 DFBRectangle dstRect
= { XLOG2DEV(dstx
), YLOG2DEV(dsty
),
709 XLOG2DEVREL(w
), YLOG2DEVREL(h
) };
711 wxIDirectFBSurfacePtr
dst(m_surface
);
713 // FIXME: this will have to be different in useMask case, see above
714 DFBSurfaceBlittingFlags blitFlag
= (src
->GetPixelFormat() == DSPF_ARGB
)
715 ? DSBLIT_BLEND_ALPHACHANNEL
717 if ( !dst
->SetBlittingFlags(blitFlag
) )
720 if ( srcRect
.w
!= dstRect
.w
|| srcRect
.h
!= dstRect
.h
)
722 // the bitmap is drawn stretched:
723 dst
->StretchBlit(src
, &srcRect
, &dstRect
);
727 // no stretching, size is preserved:
728 dst
->Blit(src
, &srcRect
, dstRect
.x
, dstRect
.y
);