Merge branch 'svg-drawtext' of https://github.com/MaartenBent/wxWidgets
Fixes and improvements to wxSVGFileDC::Draw[Rotated]Text(). See https://github.com/wxWidgets/wxWidgets/pull/1466
This commit is contained in:
@@ -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;
|
||||
|
@@ -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(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" "), x, y, w, h);
|
||||
s += wxS("style=\"") + wxBrushString(m_textBackgroundColour);
|
||||
s += wxS("stroke-width:1; ") + wxPenString(m_textBackgroundColour);
|
||||
s += wxString::Format(wxS("\" transform=\"rotate(%s %d %d)\"/>"), 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(" <text x=\"%d\" y=\"%d\" textLength=\"%d\" "), xx, yy, ww);
|
||||
|
||||
wxString fontName(m_font.GetFaceName());
|
||||
if (fontName.Len() > 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(" <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" %s %s/>\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(" <text x=\"%d\" y=\"%d\" textLength=\"%d\" %s %s>%s</text>\n"),
|
||||
xText, yText, ww, style, transform,
|
||||
#if wxUSE_MARKUP
|
||||
s += wxMarkupParser::Quote(lines[lineNum]) + wxS("</text>\n");
|
||||
wxMarkupParser::Quote(line)
|
||||
#else
|
||||
s += lines[lineNum] + wxS("</text>\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();
|
||||
}
|
||||
|
@@ -2422,6 +2422,11 @@ wxSize wxMSWDCImpl::GetPPI() const
|
||||
return wxSize(x, y);
|
||||
}
|
||||
|
||||
double wxMSWDCImpl::GetContentScaleFactor() const
|
||||
{
|
||||
return GetPPI().y / 96.0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DC caching
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user