X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9928536b3a83586c473c96000c2d3a32e4c3f576..8fdbcf4de8eeff67ccfaf3deec833d203f112629:/src/common/dcbase.cpp?ds=inline diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index ee83c03fda..6f4d456002 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -30,19 +30,25 @@ #include "wx/dcscreen.h" #include "wx/dcprint.h" #include "wx/prntbase.h" +#include "wx/scopeguard.h" #ifndef WX_PRECOMP #include "wx/math.h" #include "wx/module.h" + #include "wx/window.h" #endif +#include "wx/private/textmeasure.h" + #ifdef __WXMSW__ #include "wx/msw/dcclient.h" #include "wx/msw/dcmemory.h" #include "wx/msw/dcscreen.h" #endif -#ifdef __WXGTK20__ +#ifdef __WXGTK3__ + #include "wx/gtk/dc.h" +#elif defined __WXGTK20__ #include "wx/gtk/dcclient.h" #include "wx/gtk/dcmemory.h" #include "wx/gtk/dcscreen.h" @@ -88,12 +94,6 @@ #include "wx/dfb/dcscreen.h" #endif -#ifdef __WXPALMOS__ - #include "wx/palmos/dcclient.h" - #include "wx/palmos/dcmemory.h" - #include "wx/palmos/dcscreen.h" -#endif - //---------------------------------------------------------------------------- // wxDCFactory //---------------------------------------------------------------------------- @@ -133,17 +133,23 @@ IMPLEMENT_DYNAMIC_CLASS(wxDCFactoryCleanupModule, wxModule) wxDCImpl* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window ) { - return new wxWindowDCImpl( owner, window ); + wxDCImpl * const impl = new wxWindowDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } wxDCImpl* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window ) { - return new wxClientDCImpl( owner, window ); + wxDCImpl * const impl = new wxClientDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } wxDCImpl* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window ) { - return new wxPaintDCImpl( owner, window ); + wxDCImpl * const impl = new wxPaintDCImpl( owner, window ); + impl->InheritAttributes(window); + return impl; } wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) @@ -151,9 +157,19 @@ wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner ) return new wxMemoryDCImpl( owner ); } -wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap ) +wxDCImpl* wxNativeDCFactory::CreateMemoryDC(wxMemoryDC *owner, wxBitmap& bitmap) { - return new wxMemoryDCImpl( owner, bitmap ); + // the bitmap may be modified when it's selected into a memory DC so make + // sure changing this bitmap doesn't affect any other shallow copies of it + // (see wxMemoryDC::SelectObject()) + // + // notice that we don't provide any ctor equivalent to SelectObjectAsSource + // method because this should be rarely needed and easy to work around by + // using the default ctor and calling SelectObjectAsSource itself + if ( bitmap.IsOk() ) + bitmap.UnShare(); + + return new wxMemoryDCImpl(owner, bitmap); } wxDCImpl* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc ) @@ -219,6 +235,12 @@ wxMemoryDC::wxMemoryDC(wxDC *dc) void wxMemoryDC::SelectObject(wxBitmap& bmp) { + if ( bmp.IsSameAs(GetSelectedBitmap()) ) + { + // Nothing to do, this bitmap is already selected. + return; + } + // make sure that the given wxBitmap is not sharing its data with other // wxBitmap instances as its contents will be modified by any drawing // operation done on this DC @@ -284,12 +306,12 @@ wxPrinterDC::wxPrinterDC(const wxPrintData& data) { } -wxRect wxPrinterDC::GetPaperRect() +wxRect wxPrinterDC::GetPaperRect() const { return GetImpl()->GetPaperRect(); } -int wxPrinterDC::GetResolution() +int wxPrinterDC::GetResolution() const { return GetImpl()->GetResolution(); } @@ -347,6 +369,30 @@ wxDCImpl::~wxDCImpl() { } +// ---------------------------------------------------------------------------- +// clipping +// ---------------------------------------------------------------------------- + +void wxDCImpl::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } +} + // ---------------------------------------------------------------------------- // coordinate conversions and transforms // ---------------------------------------------------------------------------- @@ -397,7 +443,7 @@ void wxDCImpl::ComputeScaleAndOrigin() m_scaleY = m_logicalScaleY * m_userScaleY; } -void wxDCImpl::SetMapMode( int mode ) +void wxDCImpl::SetMapMode( wxMappingMode mode ) { switch (mode) { @@ -467,78 +513,10 @@ void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) ComputeScaleAndOrigin(); } - -// Each element of the widths array will be the width of the string up to and -// including the corresponding character in text. This is the generic -// implementation, the port-specific classes should do this with native APIs -// if available and if faster. Note: pango_layout_index_to_pos is much slower -// than calling GetTextExtent!! - -#define FWC_SIZE 256 - -class FontWidthCache -{ -public: - FontWidthCache() : m_scaleX(1), m_widths(NULL) { } - ~FontWidthCache() { delete []m_widths; } - - void Reset() - { - if (!m_widths) - m_widths = new int[FWC_SIZE]; - - memset(m_widths, 0, sizeof(int)*FWC_SIZE); - } - - wxFont m_font; - double m_scaleX; - int *m_widths; -}; - -static FontWidthCache s_fontWidthCache; - bool wxDCImpl::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const { - int totalWidth = 0; - - const size_t len = text.length(); - widths.Empty(); - widths.Add(0, len); - - // reset the cache if font or horizontal scale have changed - if ( !s_fontWidthCache.m_widths || - !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || - (s_fontWidthCache.m_font != GetFont()) ) - { - s_fontWidthCache.Reset(); - s_fontWidthCache.m_font = GetFont(); - s_fontWidthCache.m_scaleX = m_scaleX; - } - - // Calculate the position of each character based on the widths of - // the previous characters - int w, h; - for ( size_t i = 0; i < len; i++ ) - { - const wxChar c = text[i]; - unsigned int c_int = (unsigned int)c; - - if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) - { - w = s_fontWidthCache.m_widths[c_int]; - } - else - { - DoGetTextExtent(c, &w, &h); - if (c_int < FWC_SIZE) - s_fontWidthCache.m_widths[c_int] = w; - } - - totalWidth += w; - widths[i] = totalWidth; - } - - return true; + wxTextMeasure tm(GetOwner(), &m_font); + return tm.GetPartialTextExtents(text, widths, m_scaleX); } void wxDCImpl::GetMultiLineTextExtent(const wxString& text, @@ -547,64 +525,8 @@ void wxDCImpl::GetMultiLineTextExtent(const wxString& text, wxCoord *h, const wxFont *font) const { - wxCoord widthTextMax = 0, widthLine, - heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; - - wxString curLine; - for ( wxString::const_iterator pc = text.begin(); ; ++pc ) - { - if ( pc == text.end() || *pc == _T('\n') ) - { - if ( curLine.empty() ) - { - // we can't use GetTextExtent - it will return 0 for both width - // and height and an empty line should count in height - // calculation - - // assume that this line has the same height as the previous - // one - if ( !heightLineDefault ) - heightLineDefault = heightLine; - - if ( !heightLineDefault ) - { - // but we don't know it yet - choose something reasonable - DoGetTextExtent(_T("W"), NULL, &heightLineDefault, - NULL, NULL, font); - } - - heightTextTotal += heightLineDefault; - } - else - { - DoGetTextExtent(curLine, &widthLine, &heightLine, - NULL, NULL, font); - if ( widthLine > widthTextMax ) - widthTextMax = widthLine; - heightTextTotal += heightLine; - } - - if ( pc == text.end() ) - { - break; - } - else // '\n' - { - curLine.clear(); - } - } - else - { - curLine += *pc; - } - } - - if ( x ) - *x = widthTextMax; - if ( y ) - *y = heightTextTotal; - if ( h ) - *h = heightLine; + wxTextMeasure tm(GetOwner(), font && font->IsOk() ? font : &m_font); + tm.GetMultiLineTextExtent(text, x, y, h); } void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1, @@ -634,13 +556,13 @@ wxDCImpl::DoStretchBlit(wxCoord xdest, wxCoord ydest, wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight, - int rop, + wxRasterOperationMode rop, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask) { wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false, - _T("invalid blit size") ); + wxT("invalid blit size") ); // emulate the stretching by modifying the DC scale double xscale = (double)srcWidth/dstWidth, @@ -680,7 +602,7 @@ void wxDCImpl::DrawLines(const wxPointList *list, wxCoord xoffset, wxCoord yoffs void wxDCImpl::DrawPolygon(const wxPointList *list, wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { int n = list->GetCount(); wxPoint *points = new wxPoint[n]; @@ -700,10 +622,10 @@ void wxDCImpl::DrawPolygon(const wxPointList *list, void wxDCImpl::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], + const int count[], + const wxPoint points[], wxCoord xoffset, wxCoord yoffset, - int fillStyle) + wxPolygonFillMode fillStyle) { if ( n == 1 ) { @@ -713,7 +635,6 @@ wxDCImpl::DoDrawPolyPolygon(int n, int i, j, lastOfs; wxPoint* pts; - wxPen pen; for (i = j = lastOfs = 0; i < n; i++) { @@ -729,10 +650,11 @@ wxDCImpl::DoDrawPolyPolygon(int n, pts[j++] = pts[lastOfs]; } - pen = GetPen(); - SetPen(wxPen(*wxBLACK, 0, wxPENSTYLE_TRANSPARENT)); - DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); - SetPen(pen); + { + wxDCPenChanger setTransp(*m_owner, *wxTRANSPARENT_PEN); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + } + for (i = j = 0; i < n; i++) { DoDrawLines(count[i], pts+j, xoffset, yoffset); @@ -751,11 +673,11 @@ void wxDCImpl::DrawSpline(wxCoord x1, wxCoord y1, DrawSpline(WXSIZEOF(points), points); } -void wxDCImpl::DrawSpline(int n, wxPoint points[]) +void wxDCImpl::DrawSpline(int n, const wxPoint points[]) { wxPointList list; for ( int i = 0; i < n; i++ ) - list.Append(&points[i]); + list.Append(const_cast(&points[i])); DrawSpline(&list); } @@ -772,7 +694,7 @@ void wx_spline_push(double x1, double y1, double x2, double y2, double x3, doubl static bool wx_spline_add_point(double x, double y); static void wx_spline_draw_point_array(wxDC *dc); -wxPointList wx_spline_point_list; +static wxPointList wx_spline_point_list; #define half(z1, z2) ((z1+z2)/2.0) #define THRESHOLD 5 @@ -877,7 +799,7 @@ void wxDCImpl::DoDrawSpline( const wxPointList *points ) { wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - wxPoint *p; + const wxPoint *p; double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; double x1, y1, x2, y2; @@ -886,7 +808,7 @@ void wxDCImpl::DoDrawSpline( const wxPointList *points ) // empty list return; - p = (wxPoint *)node->GetData(); + p = node->GetData(); x1 = p->x; y1 = p->y; @@ -904,9 +826,9 @@ void wxDCImpl::DoDrawSpline( const wxPointList *points ) wx_spline_add_point(x1, y1); while ((node = node->GetNext()) -#if !wxUSE_STL +#if !wxUSE_STD_CONTAINERS != NULL -#endif // !wxUSE_STL +#endif // !wxUSE_STD_CONTAINERS ) { p = node->GetData(); @@ -1038,8 +960,9 @@ void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, const wxColour& destColour, const wxPoint& circleCenter) { - //save the old pen color - wxColour oldPenColour = m_pen.GetColour(); + // save the old pen and ensure it is restored on exit + const wxPen penOrig = m_pen; + wxON_BLOCK_EXIT_SET(m_pen, penOrig); wxUint8 nR1 = destColour.Red(); wxUint8 nG1 = destColour.Green(); @@ -1051,45 +974,84 @@ void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; + double cx = rect.GetWidth() / 2; + double cy = rect.GetHeight() / 2; + double dRadius; if (cx < cy) - nRadius = cx; + dRadius = cx; else - nRadius = cy; + dRadius = cy; //Offset of circle - wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); - wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); + double ptX, ptY; + ptX = circleCenter.x; + ptY = circleCenter.y; + double nCircleOffX = ptX - cx; + double nCircleOffY = ptY - cy; + + double dGradient; + double dx, dy; for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) { for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) { //get color difference - wxInt32 nGradient = ((nRadius - - (wxInt32)sqrt( - pow((double)(x - cx - nCircleOffX), 2) + - pow((double)(y - cy - nCircleOffY), 2) - )) * 100) / nRadius; + dx = x; + dy = y; + + dGradient = ((dRadius - sqrt( (dx - cx - nCircleOffX) * (dx - cx - nCircleOffX) + +(dy - cy - nCircleOffY) * (dy - cy - nCircleOffY) + ) + ) * 100 + ) / dRadius; //normalize Gradient - if (nGradient < 0 ) - nGradient = 0; + if (dGradient < 0) + dGradient = 0.0; //get dest colors - nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); - nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); - nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); + nR = (wxUint8)(nR1 + ((nR2 - nR1) * dGradient / 100)); + nG = (wxUint8)(nG1 + ((nG2 - nG1) * dGradient / 100)); + nB = (wxUint8)(nB1 + ((nB2 - nB1) * dGradient / 100)); //set the pixel - m_pen.SetColour(wxColour(nR,nG,nB)); + SetPen(wxColour(nR,nG,nB)); DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop()); } } - //return old pen color - m_pen.SetColour(oldPenColour); +} + +void wxDCImpl::InheritAttributes(wxWindow *win) +{ + wxCHECK_RET( win, "window can't be NULL" ); + + SetFont(win->GetFont()); + SetTextForeground(win->GetForegroundColour()); + SetTextBackground(win->GetBackgroundColour()); + SetBackground(win->GetBackgroundColour()); + SetLayoutDirection(win->GetLayoutDirection()); +} + +void wxDCImpl::DoGetFontMetrics(int *height, + int *ascent, + int *descent, + int *internalLeading, + int *externalLeading, + int *averageWidth) const +{ + // Average width is typically the same as width of 'x'. + wxCoord h, d; + DoGetTextExtent("x", averageWidth, &h, &d, externalLeading); + + if ( height ) + *height = h; + if ( ascent ) + *ascent = h - d; + if ( descent ) + *descent = d; + if ( internalLeading ) + *internalLeading = 0; } //----------------------------------------------------------------------------- @@ -1098,6 +1060,15 @@ void wxDCImpl::DoGradientFillConcentric(const wxRect& rect, IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject) +void wxDC::CopyAttributes(const wxDC& dc) +{ + SetFont(dc.GetFont()); + SetTextForeground(dc.GetTextForeground()); + SetTextBackground(dc.GetTextBackground()); + SetBackground(dc.GetBackground()); + SetLayoutDirection(dc.GetLayoutDirection()); +} + void wxDC::DrawLabel(const wxString& text, const wxBitmap& bitmap, const wxRect& rect, @@ -1110,7 +1081,7 @@ void wxDC::DrawLabel(const wxString& text, GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); wxCoord width, height; - if ( bitmap.Ok() ) + if ( bitmap.IsOk() ) { width = widthText + bitmap.GetWidth(); height = bitmap.GetHeight(); @@ -1152,7 +1123,7 @@ void wxDC::DrawLabel(const wxString& text, wxCoord x0 = x, y0 = y, width0 = width; - if ( bitmap.Ok() ) + if ( bitmap.IsOk() ) { DrawBitmap(bitmap, x, y, true /* use mask */); @@ -1169,6 +1140,12 @@ void wxDC::DrawLabel(const wxString& text, yUnderscore = 0; // split the string into lines and draw each of them separately + // + // NB: while wxDC::DrawText() on some platforms supports drawing multi-line + // strings natively, this is not the case for all of them, notably not + // wxMSW which uses this function for multi-line texts, so we may only + // call DrawText() for single-line strings from here to avoid infinite + // recursion. wxString curLine; for ( wxString::const_iterator pc = text.begin(); ; ++pc ) { @@ -1219,7 +1196,7 @@ void wxDC::DrawLabel(const wxString& text, { if ( pc - text.begin() == indexAccel ) { - // remeber to draw underscore here + // remember to draw underscore here GetTextExtent(curLine, &startUnderscore, NULL); curLine += *pc; GetTextExtent(curLine, &endUnderscore, NULL); @@ -1239,7 +1216,14 @@ void wxDC::DrawLabel(const wxString& text, // it should be of the same colour as text SetPen(wxPen(GetTextForeground(), 0, wxPENSTYLE_SOLID)); - yUnderscore--; + // This adjustment is relatively arbitrary: we need to draw the + // underline slightly higher to avoid overflowing the character cell + // but whether we should do it 1, 2 or 3 pixels higher is not clear. + // + // The currently used value seems to be compatible with native MSW + // behaviour, i.e. it results in the same appearance of the owner-drawn + // and normal labels. + yUnderscore -= 2; DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); } @@ -1306,6 +1290,13 @@ void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const if (h) *h = hh; } +void wxDC::DrawObject(wxDrawObject* drawobject) +{ + drawobject->Draw(*this); + CalcBoundingBox(drawobject->MinX(),drawobject->MinY()); + CalcBoundingBox(drawobject->MaxX(),drawobject->MaxY()); +} + #endif // WXWIN_COMPATIBILITY_2_8 /* @@ -1510,7 +1501,7 @@ void wxDCImpl::CalculateEllipticPoints( wxPointList* points, y2 = y2-y-y+1; --y; } - // old y now to big: set point with old y, old x + // old y now too big: set point with old y, old x if( bNewPoint && x>1) { int x1 = x - 1; @@ -1622,3 +1613,15 @@ void wxDCImpl::CalculateEllipticPoints( wxPointList* points, } // CalculateEllipticPoints #endif // __WXWINCE__ + +float wxDCImpl::GetFontPointSizeAdjustment(float dpi) +{ + // wxMSW has long-standing bug where wxFont point size is interpreted as + // "pixel size corresponding to given point size *on screen*". In other + // words, on a typical 600dpi printer and a typical 96dpi screen, fonts + // are ~6 times smaller when printing. Unfortunately, this bug is so severe + // that *all* printing code has to account for it and consequently, other + // ports need to emulate this bug too: + const wxSize screenPPI = wxGetDisplayPPI(); + return float(screenPPI.y) / dpi; +}