+wxCoord wxDCImpl::DeviceToLogicalX(wxCoord x) const
+{
+ return wxRound( (double)((x - m_deviceOriginX - m_deviceLocalOriginX) * m_signX) / m_scaleX ) + m_logicalOriginX ;
+}
+
+wxCoord wxDCImpl::DeviceToLogicalY(wxCoord y) const
+{
+ return wxRound( (double)((y - m_deviceOriginY - m_deviceLocalOriginY) * m_signY) / m_scaleY ) + m_logicalOriginY ;
+}
+
+wxCoord wxDCImpl::DeviceToLogicalXRel(wxCoord x) const
+{
+ return wxRound((double)(x) / m_scaleX);
+}
+
+wxCoord wxDCImpl::DeviceToLogicalYRel(wxCoord y) const
+{
+ return wxRound((double)(y) / m_scaleY);
+}
+
+wxCoord wxDCImpl::LogicalToDeviceX(wxCoord x) const
+{
+ return wxRound( (double)((x - m_logicalOriginX) * m_signX) * m_scaleX) + m_deviceOriginX + m_deviceLocalOriginX;
+}
+
+wxCoord wxDCImpl::LogicalToDeviceY(wxCoord y) const
+{
+ return wxRound( (double)((y - m_logicalOriginY) * m_signY) * m_scaleY) + m_deviceOriginY + m_deviceLocalOriginY;
+}
+
+wxCoord wxDCImpl::LogicalToDeviceXRel(wxCoord x) const
+{
+ return wxRound((double)(x) * m_scaleX);
+}
+
+wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const
+{
+ return wxRound((double)(y) * m_scaleY);
+}
+
+void wxDCImpl::ComputeScaleAndOrigin()
+{
+ m_scaleX = m_logicalScaleX * m_userScaleX;
+ m_scaleY = m_logicalScaleY * m_userScaleY;
+}
+
+void wxDCImpl::SetMapMode( int mode )
+{
+ switch (mode)
+ {
+ case wxMM_TWIPS:
+ SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
+ break;
+ case wxMM_POINTS:
+ SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
+ break;
+ case wxMM_METRIC:
+ SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
+ break;
+ case wxMM_LOMETRIC:
+ SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
+ break;
+ default:
+ case wxMM_TEXT:
+ SetLogicalScale( 1.0, 1.0 );
+ break;
+ }
+ m_mappingMode = mode;
+}
+
+void wxDCImpl::SetUserScale( double x, double y )
+{
+ // allow negative ? -> no
+ m_userScaleX = x;
+ m_userScaleY = y;
+ ComputeScaleAndOrigin();
+}
+
+void wxDCImpl::SetLogicalScale( double x, double y )
+{
+ // allow negative ?
+ m_logicalScaleX = x;
+ m_logicalScaleY = y;
+ ComputeScaleAndOrigin();
+}
+
+void wxDCImpl::SetLogicalOrigin( wxCoord x, wxCoord y )
+{
+ m_logicalOriginX = x * m_signX;
+ m_logicalOriginY = y * m_signY;
+ ComputeScaleAndOrigin();
+}
+
+void wxDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
+{
+ m_deviceOriginX = x;
+ m_deviceOriginY = y;
+ ComputeScaleAndOrigin();
+}
+
+void wxDCImpl::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
+{
+ m_deviceLocalOriginX = x;
+ m_deviceLocalOriginY = y;
+ ComputeScaleAndOrigin();
+}
+
+void wxDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
+{
+ // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
+ // wxWidgets 2.9: no longer override it
+ m_signX = (xLeftRight ? 1 : -1);
+ m_signY = (yBottomUp ? -1 : 1);
+ 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;
+}
+
+void wxDCImpl::GetMultiLineTextExtent(const wxString& text,
+ wxCoord *x,
+ wxCoord *y,
+ 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;
+}
+
+void wxDCImpl::DoDrawCheckMark(wxCoord x1, wxCoord y1,