]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/textmeasurecmn.cpp
Workaround for #15404: wxRichTextCtrl: caret does not disappear when focus is lost...
[wxWidgets.git] / src / common / textmeasurecmn.cpp
index 90894bf0c603bcc205f64b5c735c5b7686239b2c..8d828d4b714a77cdd76673f5278f8135fecc6e77 100644 (file)
@@ -3,7 +3,6 @@
 // Purpose:     wxTextMeasureBase implementation
 // Author:      Manuel Martin
 // Created:     2012-10-05
-// RCS-ID:      $Id:
 // Copyright:   (c) 1997-2012 wxWidgets team
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
@@ -36,6 +35,10 @@ wxTextMeasureBase::wxTextMeasureBase(const wxDC *dc, const wxFont *theFont)
       m_font(theFont)
 {
     wxASSERT_MSG( dc, wxS("wxTextMeasure needs a valid wxDC") );
+
+    // By default, use wxDC version, we'll explicitly reset this to false in
+    // the derived classes if the DC is of native variety.
+    m_useDCImpl = true;
 }
 
 wxTextMeasureBase::wxTextMeasureBase(const wxWindow *win, const wxFont *theFont)
@@ -44,6 +47,28 @@ wxTextMeasureBase::wxTextMeasureBase(const wxWindow *win, const wxFont *theFont)
       m_font(theFont)
 {
     wxASSERT_MSG( win, wxS("wxTextMeasure needs a valid wxWindow") );
+
+    // We don't have any wxDC so we can't forward to it.
+    m_useDCImpl = false;
+}
+
+wxFont wxTextMeasureBase::GetFont() const
+{
+    return m_font ? *m_font
+                  : m_win ? m_win->GetFont()
+                          : m_dc->GetFont();
+}
+
+void wxTextMeasureBase::CallGetTextExtent(const wxString& string,
+                                          wxCoord *width,
+                                          wxCoord *height,
+                                          wxCoord *descent,
+                                          wxCoord *externalLeading)
+{
+    if ( m_useDCImpl )
+        m_dc->GetTextExtent(string, width, height, descent, externalLeading);
+    else
+        DoGetTextExtent(string, width, height, descent, externalLeading);
 }
 
 void wxTextMeasureBase::GetTextExtent(const wxString& string,
@@ -60,7 +85,9 @@ void wxTextMeasureBase::GetTextExtent(const wxString& string,
     if ( !height )
         height = &unusedHeight;
 
-    if ( string.empty() )
+    // Avoid even setting up the DC for measuring if we don't actually need to
+    // measure anything.
+    if ( string.empty() && !descent && !externalLeading )
     {
         *width =
         *height = 0;
@@ -70,7 +97,7 @@ void wxTextMeasureBase::GetTextExtent(const wxString& string,
 
     MeasuringGuard guard(*this);
 
-    DoGetTextExtent(string, width, height, descent, externalLeading);
+    CallGetTextExtent(string, width, height, descent, externalLeading);
 }
 
 void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
@@ -103,14 +130,14 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
                 {
                     // but we don't know it yet - choose something reasonable
                     int dummy;
-                    DoGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
+                    CallGetTextExtent(wxS("W"), &dummy, &heightLineDefault);
                 }
 
                 heightTextTotal += heightLineDefault;
             }
             else
             {
-                DoGetTextExtent(curLine, &widthLine, &heightLine);
+                CallGetTextExtent(curLine, &widthLine, &heightLine);
                 if ( widthLine > widthTextMax )
                     widthTextMax = widthLine;
                 heightTextTotal += heightLine;
@@ -139,18 +166,15 @@ void wxTextMeasureBase::GetMultiLineTextExtent(const wxString& text,
         *heightOneLine = heightLine;
 }
 
-void wxTextMeasureBase::GetLargestStringExtent(const wxVector<wxString>& strings,
-                                               wxCoord *width,
-                                               wxCoord *height)
+wxSize wxTextMeasureBase::GetLargestStringExtent(size_t n,
+                                                 const wxString* strings)
 {
     MeasuringGuard guard(*this);
 
     wxCoord w, h, widthMax = 0, heightMax = 0;
-    for ( wxVector<wxString>::const_iterator i = strings.begin();
-          i != strings.end();
-          ++i )
+    for ( size_t i = 0; i < n; ++i )
     {
-        DoGetTextExtent(*i, &w, &h);
+        CallGetTextExtent(strings[i], &w, &h);
 
         if ( w > widthMax )
             widthMax = w;
@@ -158,10 +182,7 @@ void wxTextMeasureBase::GetLargestStringExtent(const wxVector<wxString>& strings
             heightMax = h;
     }
 
-    if ( width )
-        *width = widthMax;
-    if ( height )
-        *height = heightMax;
+    return wxSize(widthMax, heightMax);
 }
 
 bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
@@ -178,3 +199,82 @@ bool wxTextMeasureBase::GetPartialTextExtents(const wxString& text,
 
     return DoGetPartialTextExtents(text, widths, scaleX);
 }
+
+// ----------------------------------------------------------------------------
+// Generic and inefficient DoGetPartialTextExtents() implementation.
+// ----------------------------------------------------------------------------
+
+// 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 wxTextMeasureBase::DoGetPartialTextExtents(const wxString& text,
+                                                wxArrayInt& widths,
+                                                double scaleX)
+{
+    int totalWidth = 0;
+
+    // reset the cache if font or horizontal scale have changed
+    if ( !s_fontWidthCache.m_widths ||
+         !wxIsSameDouble(s_fontWidthCache.m_scaleX, scaleX) ||
+         (s_fontWidthCache.m_font != *m_font) )
+    {
+        s_fontWidthCache.Reset();
+        s_fontWidthCache.m_font = *m_font;
+        s_fontWidthCache.m_scaleX = scaleX;
+    }
+
+    // Calculate the position of each character based on the widths of
+    // the previous characters. This is inexact for not fixed fonts.
+    int n = 0;
+    for ( wxString::const_iterator it = text.begin();
+          it != text.end();
+          ++it )
+    {
+        const wxChar c = *it;
+        unsigned int c_int = (unsigned int)c;
+
+        int w;
+        if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
+        {
+            w = s_fontWidthCache.m_widths[c_int];
+        }
+        else
+        {
+            DoGetTextExtent(c, &w, NULL);
+            if (c_int < FWC_SIZE)
+                s_fontWidthCache.m_widths[c_int] = w;
+        }
+
+        totalWidth += w;
+        widths[n++] = totalWidth;
+    }
+
+    return true;
+}
+