diff --git a/include/wx/msw/dc.h b/include/wx/msw/dc.h
index a27b70dab3..50dd717d9f 100644
--- a/include/wx/msw/dc.h
+++ b/include/wx/msw/dc.h
@@ -77,6 +77,7 @@ public:
virtual bool CanGetTextExtent() const wxOVERRIDE;
virtual int GetDepth() const wxOVERRIDE;
virtual wxSize GetPPI() const wxOVERRIDE;
+ virtual double GetContentScaleFactor() const wxOVERRIDE;
virtual void SetMapMode(wxMappingMode mode) wxOVERRIDE;
diff --git a/src/common/dcsvg.cpp b/src/common/dcsvg.cpp
index 6b9cab2b3b..6229cd863f 100644
--- a/src/common/dcsvg.cpp
+++ b/src/common/dcsvg.cpp
@@ -273,6 +273,28 @@ wxString wxCreateBrushFill(wxBrush& brush)
return s;
}
+void wxSetScaledScreenDCFont(wxScreenDC& sDC, const wxFont& font)
+{
+ const double scale = sDC.GetContentScaleFactor();
+ if ( scale > 1 )
+ {
+ // wxScreenDC uses the DPI of the main screen to determine the text
+ // extent and character width/height. Because the SVG should be
+ // DPI-independent we want the text extent of the default (96) DPI.
+ //
+ // We can't just divide the returned sizes by the scale factor, because
+ // text does not scale linear (at least on Windows). Therefore, we scale
+ // the font size instead.
+ wxFont scaledFont = font;
+ scaledFont.SetFractionalPointSize(scaledFont.GetFractionalPointSize() / scale);
+ sDC.SetFont(scaledFont);
+ }
+ else
+ {
+ sDC.SetFont(font);
+ }
+}
+
} // anonymous namespace
// ----------------------------------------------------------------------------
@@ -535,93 +557,100 @@ void wxSVGFileDCImpl::DoDrawRotatedText(const wxString& sText, wxCoord x, wxCoor
const double dx = heightLine * sin(rad);
const double dy = heightLine * cos(rad);
- // wxS("upper left") and wxS("upper right")
+ // Update bounding box: upper left, upper right, bottom left, bottom right
CalcBoundingBox(x, y);
CalcBoundingBox((wxCoord)(x + w * cos(rad)), (wxCoord)(y - h * sin(rad)));
-
- // wxS("bottom left") and wxS("bottom right")
CalcBoundingBox((wxCoord)(x + h * sin(rad)), (wxCoord)(y + h * cos(rad)));
CalcBoundingBox((wxCoord)(x + h * sin(rad) + w * cos(rad)), (wxCoord)(y + h * cos(rad) - w * sin(rad)));
- if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
+ // Create text style string
+ wxString fontstyle;
+ switch (m_font.GetStyle())
{
- // draw background first
- // just like DoDrawRectangle except we pass the text color to it and set the border to a 1 pixel wide text background
- s += wxString::Format(wxS(" "), NumStr(-angle), x, y);
- s += wxS("\n");
- write(s);
+ case wxFONTSTYLE_MAX:
+ wxFAIL_MSG(wxS("invalid font style value"));
+ wxFALLTHROUGH;
+ case wxFONTSTYLE_NORMAL:
+ fontstyle = wxS("normal");
+ break;
+ case wxFONTSTYLE_ITALIC:
+ fontstyle = wxS("italic");
+ break;
+ case wxFONTSTYLE_SLANT:
+ fontstyle = wxS("oblique");
+ break;
}
+ wxString textDecoration;
+ if (m_font.GetUnderlined())
+ textDecoration += wxS(" underline");
+ if (m_font.GetStrikethrough())
+ textDecoration += wxS(" line-through");
+ if (textDecoration.IsEmpty())
+ textDecoration = wxS(" none");
+
+ wxString style = wxS("style=\"");
+ style += wxString::Format(wxS("font-family:%s; "), m_font.GetFaceName());
+ style += wxString::Format(wxS("font-weight:%d; "), m_font.GetWeight());
+ style += wxString::Format(wxS("font-style:%s; "), fontstyle);
+ style += wxString::Format(wxS("font-size:%spt; "), NumStr(m_font.GetFractionalPointSize()));
+ style += wxString::Format(wxS("text-decoration:%s; "), textDecoration);
+ style += wxString::Format(wxS("%s %s stroke-width:0; "),
+ wxBrushString(m_textForegroundColour),
+ wxPenString(m_textForegroundColour));
+ style += wxS("white-space: pre;");
+ style += wxS("\"");
+
+ // this is deprecated in favour of "white-space: pre", keep it for now to
+ // support SVG viewers that do not support the new tag
+ style += wxS(" xml:space=\"preserve\"");
+
// Draw all text line by line
const wxArrayString lines = wxSplit(sText, '\n', '\0');
for (size_t lineNum = 0; lineNum < lines.size(); lineNum++)
{
+ const int xRect = x + wxRound(lineNum * dx);
+ const int yRect = y + wxRound(lineNum * dy);
+
// convert x,y to SVG text x,y (the coordinates of the text baseline)
wxCoord ww, hh, desc;
- DoGetTextExtent(lines[lineNum], &ww, &hh, &desc);
- int xx = x + wxRound(lineNum * dx) + (hh - desc) * sin(rad);
- int yy = y + wxRound(lineNum * dy) + (hh - desc) * cos(rad);
+ wxString const& line = lines[lineNum];
+ DoGetTextExtent(line, &ww, &hh, &desc);
+ const int xText = xRect + (hh - desc) * sin(rad);
+ const int yText = yRect + (hh - desc) * cos(rad);
- //now do the text itself
- s += wxString::Format(wxS(" 0)
- s += wxS("style=\"font-family:") + fontName + wxS("; ");
- else
- s += wxS("style=\" ");
-
- wxString fontweight = wxString::Format(wxS("%d"), m_font.GetWeight());
-
- s += wxS("font-weight:") + fontweight + wxS("; ");
-
- wxString fontstyle;
- switch (m_font.GetStyle())
+ if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
{
- case wxFONTSTYLE_MAX:
- wxFAIL_MSG(wxS("invalid font style value"));
- wxFALLTHROUGH;
+ // draw text background
+ const wxString rectStyle = wxString::Format(
+ wxS("style=\"%s %s stroke-width:1;\""),
+ wxBrushString(m_textBackgroundColour),
+ wxPenString(m_textBackgroundColour));
- case wxFONTSTYLE_NORMAL:
- fontstyle = wxS("normal");
- break;
+ const wxString rectTransform = wxString::Format(
+ wxS("transform=\"rotate(%s %d %d)\""),
+ NumStr(-angle), xRect, yRect);
- case wxFONTSTYLE_ITALIC:
- fontstyle = wxS("italic");
- break;
+ s = wxString::Format(
+ wxS(" \n"),
+ xRect, yRect, ww, hh, rectStyle, rectTransform);
- case wxFONTSTYLE_SLANT:
- fontstyle = wxS("oblique");
- break;
+ write(s);
}
- wxASSERT_MSG(!fontstyle.empty(), wxS("unknown font style value"));
+ const wxString transform = wxString::Format(
+ wxS("transform=\"rotate(%s %d %d)\""),
+ NumStr(-angle), xText, yText);
- s += wxS("font-style:") + fontstyle + wxS("; ");
-
- wxString textDecoration;
- if (m_font.GetUnderlined())
- textDecoration += wxS(" underline");
- if (m_font.GetStrikethrough())
- textDecoration += wxS(" line-through");
- if (textDecoration.IsEmpty())
- textDecoration = wxS(" none");
-
- s += wxS("text-decoration:") + textDecoration + wxS("; ");
-
- s += wxString::Format(wxS("font-size:%dpt; "), m_font.GetPointSize());
- //text will be solid, unless alpha value isn't opaque in the foreground colour
- s += wxBrushString(m_textForegroundColour) + wxPenString(m_textForegroundColour);
- s += wxString::Format(wxS("stroke-width:0;\" transform=\"rotate(%s %d %d)\""), NumStr(-angle), xx, yy);
- s += wxS(" xml:space=\"preserve\">");
+ s = wxString::Format(
+ wxS(" %s\n"),
+ xText, yText, ww, style, transform,
#if wxUSE_MARKUP
- s += wxMarkupParser::Quote(lines[lineNum]) + wxS("\n");
+ wxMarkupParser::Quote(line)
#else
- s += lines[lineNum] + wxS("\n");
+ line
#endif
+ );
write(s);
}
@@ -949,17 +978,15 @@ void wxSVGFileDCImpl::DestroyClippingRegion()
void wxSVGFileDCImpl::DoGetTextExtent(const wxString& string, wxCoord *w, wxCoord *h, wxCoord *descent, wxCoord *externalLeading, const wxFont *font) const
{
wxScreenDC sDC;
+ wxSetScaledScreenDCFont(sDC, font ? *font : m_font);
- sDC.SetFont(m_font);
- if (font != NULL)
- sDC.SetFont(*font);
sDC.GetTextExtent(string, w, h, descent, externalLeading);
}
wxCoord wxSVGFileDCImpl::GetCharHeight() const
{
wxScreenDC sDC;
- sDC.SetFont(m_font);
+ wxSetScaledScreenDCFont(sDC, m_font);
return sDC.GetCharHeight();
@@ -968,7 +995,7 @@ wxCoord wxSVGFileDCImpl::GetCharHeight() const
wxCoord wxSVGFileDCImpl::GetCharWidth() const
{
wxScreenDC sDC;
- sDC.SetFont(m_font);
+ wxSetScaledScreenDCFont(sDC, m_font);
return sDC.GetCharWidth();
}
diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp
index 13bf1135f0..6710f8c2ae 100644
--- a/src/msw/dc.cpp
+++ b/src/msw/dc.cpp
@@ -2422,6 +2422,11 @@ wxSize wxMSWDCImpl::GetPPI() const
return wxSize(x, y);
}
+double wxMSWDCImpl::GetContentScaleFactor() const
+{
+ return GetPPI().y / 96.0;
+}
+
// ----------------------------------------------------------------------------
// DC caching
// ----------------------------------------------------------------------------