void wxSVGCanvasCairo::DrawCanvasPath(wxSVGCanvasPathCairo& canvasPath, wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { // check Filter if (style.GetFilter().GetCSSPrimitiveType() == wxCSS_URI && style.GetFilter().GetStringValue().length() > 1) { wxString filterId = style.GetFilter().GetStringValue().substr(1); wxSVGElement* filterElem = (wxSVGElement*) svgElem.GetElementById(filterId); // feGaussianBlur if (filterElem && filterElem->GetDtd() == wxSVG_FILTER_ELEMENT && filterElem->GetFirstChild() != NULL && ((wxSVGSVGElement*) filterElem->GetFirstChild())->GetDtd() == wxSVG_FEGAUSSIANBLUR_ELEMENT) { float stdX = ((wxSVGFEGaussianBlurElement*) filterElem->GetFirstChild())->GetStdDeviationX().GetAnimVal(); float stdY = ((wxSVGFEGaussianBlurElement*) filterElem->GetFirstChild())->GetStdDeviationY().GetAnimVal(); if (stdX <= 0 || stdY <= 0) return; int dx = int(floor(stdX * 3 * sqrt(2 * M_PI) / 4 + 0.5)); int dy = int(floor(stdY * 3 * sqrt(2 * M_PI) / 4 + 0.5)); wxSVGRect rect = canvasPath.GetResultBBox(style, matrix.Inverse()); rect.SetX(rect.GetX() - 2*dx); rect.SetY(rect.GetY() - 2*dy); rect.SetWidth(rect.GetWidth() + 4*dx); rect.SetHeight(rect.GetHeight() + 4*dy); int width = (int) rect.GetWidth(); int height = (int) rect.GetHeight(); cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t* cr = cairo_create(surface); wxSVGMatrix matrix2 = wxSVGMatrix(1, 0, 0, 1, - rect.GetX(), - rect.GetY()).Multiply(matrix); DrawPath(cr, canvasPath, matrix2, style, svgElem); gaussianBlur(surface, dx, dy); // draw surface cairo_save(m_cr); SetMatrix(m_cr, wxSVGMatrix(1, 0, 0, 1, rect.GetX(), rect.GetY())); cairo_set_source_surface(m_cr, surface, 0, 0); cairo_rectangle(m_cr, 0, 0, width, height); cairo_paint(m_cr); // fill the rectangle using the pattern cairo_new_path(m_cr); cairo_restore(m_cr); cairo_destroy(cr); cairo_surface_destroy(surface); return; } } DrawPath(m_cr, canvasPath, matrix, style, svgElem); }
unsigned int wxSVGCanvas::GetGradientStops(const wxSVGSVGElement& svgElem, wxSVGGradientElement* gradElem, float opacity) { if (gradElem == NULL) return 0; // Search for the most referenced gradient (we assume that this is the one that contain stops) while (true) { wxString grad_href = gradElem->GetHref(); if (grad_href.length() <= 1 || grad_href.GetChar(0) != wxT('#')) break; wxSVGElement* tmp = (wxSVGSVGElement*) svgElem.GetElementById(grad_href.substr(1)); if (tmp == NULL || (tmp->GetDtd() != wxSVG_LINEARGRADIENT_ELEMENT && tmp->GetDtd() != wxSVG_RADIALGRADIENT_ELEMENT)) break; gradElem = (wxSVGGradientElement*) tmp; } // Count number of stop element wxSVGStopElement* stop_elem = (wxSVGStopElement*) gradElem->GetChildren(); unsigned int stop_count = 0; while (stop_elem) { if (stop_elem->GetDtd() == wxSVG_STOP_ELEMENT) stop_count++; stop_elem = (wxSVGStopElement*) stop_elem->GetNext(); } if (stop_count == 0) return 0; // Allocate enough stops AllocateGradientStops(stop_count); // Fill the stops stop_elem = (wxSVGStopElement*) gradElem->GetChildren(); int i = 0; while (stop_elem) { if (stop_elem->GetDtd() == wxSVG_STOP_ELEMENT) SetStopValue(i++, stop_elem->GetOffset(), stop_elem->GetStopOpacity() * opacity, stop_elem->GetStopColor().GetRGBColor()); stop_elem = (wxSVGStopElement*) stop_elem->GetNext(); } return stop_count; }
unsigned int wxSVGCanvas::GetGradientStops(const wxSVGSVGElement& svgElem, wxSVGGradientElement* gradElem, float opacity) { if (gradElem == NULL) return 0; // Search for the most referenced gradient (we assume that this is the one that contain stops) while (true) { wxString grad_href = gradElem->GetHref(); if (grad_href.length() <= 1 || grad_href.GetChar(0) != wxT('#')) break; wxSVGElement* tmp = (wxSVGSVGElement*) svgElem.GetElementById(grad_href.substr(1)); if (tmp == NULL || (tmp->GetDtd() != wxSVG_LINEARGRADIENT_ELEMENT && tmp->GetDtd() != wxSVG_RADIALGRADIENT_ELEMENT)) break; gradElem = (wxSVGGradientElement*) tmp; } // Count number of stop element wxSVGStopElement* stop_elem = (wxSVGStopElement*) gradElem->GetChildren(); unsigned int stop_count = 0; while (stop_elem) { if (stop_elem->GetDtd() == wxSVG_STOP_ELEMENT) stop_count++; stop_elem = (wxSVGStopElement*) stop_elem->GetNext(); } if (stop_count == 0) return 0; // Allocate enough stops AllocateGradientStops(stop_count); // Fill the stops stop_elem = (wxSVGStopElement*) gradElem->GetChildren(); int i = 0; while (stop_elem) { if (stop_elem->GetDtd() == wxSVG_STOP_ELEMENT) { wxSVGColor color = stop_elem->GetStopColor(); // no color, default is black if (color.GetColorType() == wxSVG_COLORTYPE_UNKNOWN) color = wxSVGColor(0,0,0); SetStopValue(i++, stop_elem->GetOffset(), stop_elem->GetStopOpacity() * opacity, color.GetRGBColor()); stop_elem = (wxSVGStopElement*) stop_elem->GetNext(); } return stop_count; } void wxSVGCanvas::GetLinearGradientVector(wxSVGPoint& p1, wxSVGPoint& p2, const wxSVGLinearGradientElement& gradElem, wxSVGCanvasPath& path) { p1.SetX(gradElem.GetX1().GetAnimVal()); p1.SetY(gradElem.GetY1().GetAnimVal()); p2.SetX(gradElem.GetX2().GetAnimVal()); p2.SetY(gradElem.GetY2().GetAnimVal()); if (gradElem.GetGradientUnits().GetAnimVal() == wxSVG_UNIT_TYPE_UNKNOWN || gradElem.GetGradientUnits().GetAnimVal() == wxSVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { wxSVGRect bbox = path.GetBBox(); p1.SetX(bbox.GetX() + p1.GetX()*bbox.GetWidth()); p1.SetY(bbox.GetY() + p1.GetY()*bbox.GetHeight()); p2.SetX(bbox.GetX() + p2.GetX()*bbox.GetWidth()); p2.SetY(bbox.GetY() + p2.GetY()*bbox.GetHeight()); } // Compute gradient transformation matrix wxSVGMatrix lg_matrix; const wxSVGTransformList& transforms = gradElem.GetGradientTransform().GetAnimVal(); for (int i=0; i<(int)transforms.Count(); i++) lg_matrix = lg_matrix.Multiply(transforms[i].GetMatrix()); p1 = p1.MatrixTransform(lg_matrix); p2 = p2.MatrixTransform(lg_matrix); }
void wxSVGCanvasCairo::DrawCanvasImage(wxSVGCanvasImage& canvasImage, cairo_surface_t* cairoSurface, wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { if (cairoSurface == NULL) return; cairo_save(m_cr); // ClipPath if (style.GetClipPath().GetCSSPrimitiveType() == wxCSS_URI && style.GetClipPath().GetStringValue().length() > 1) { wxString clipPathId = style.GetClipPath().GetStringValue().substr(1); wxSVGClipPathElement* clipPathElem = (wxSVGClipPathElement*) svgElem.GetElementById(clipPathId); if (clipPathElem && clipPathElem->GetDtd() == wxSVG_CLIPPATH_ELEMENT) { clipPathElem->SetOwnerSVGElement(&svgElem); clipPathElem->SetViewportElement(&svgElem); wxSVGMatrix clipMatrix(matrix); clipPathElem->UpdateMatrix(clipMatrix); SetClipPath(clipPathElem, clipMatrix); } } SetMatrix(m_cr, matrix); // scale context double x = canvasImage.m_x; double y = canvasImage.m_y; double scaleX = canvasImage.m_width / canvasImage.m_image.GetWidth(); double scaleY = canvasImage.m_height / canvasImage.m_image.GetHeight(); wxSVG_PRESERVEASPECTRATIO align = canvasImage.GetPreserveAspectRatio().GetAlign(); bool alignX = false; if (align > wxSVG_PRESERVEASPECTRATIO_NONE) { scaleY = canvasImage.m_height / canvasImage.GetDefaultHeight(); if (canvasImage.GetPreserveAspectRatio().GetMeetOrSlice() != wxSVG_MEETORSLICE_SLICE) { alignX = scaleX > scaleY; } else { cairo_rectangle(m_cr, x, y, canvasImage.m_width, canvasImage.m_height); cairo_clip(m_cr); alignX = scaleX < scaleY; } if (alignX) { scaleX = scaleY; if (align == wxSVG_PRESERVEASPECTRATIO_XMIDYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX) x += (canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMAXYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) x += canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX; } else { scaleY = scaleX; if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID) y += (canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) y += canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY; } scaleY = scaleY * canvasImage.GetDefaultHeight() / canvasImage.m_image.GetHeight(); } cairo_translate(m_cr, x, y); cairo_scale(m_cr, scaleX, scaleY); // prepare to draw the image cairo_set_source_surface(m_cr, cairoSurface, 0, 0); // use the original size here since the context is scaled already... cairo_rectangle(m_cr, 0, 0, canvasImage.m_image.GetWidth(), canvasImage.m_image.GetHeight()); // paint if (style.GetMask().GetCSSPrimitiveType() == wxCSS_URI && style.GetMask().GetStringValue().length() > 1) { wxString maskId = style.GetMask().GetStringValue().substr(1); wxSVGMaskElement* maskElem = (wxSVGMaskElement*) svgElem.GetElementById(maskId); if (maskElem && maskElem->GetDtd() == wxSVG_MASK_ELEMENT) { maskElem->SetOwnerSVGElement(&svgElem); maskElem->SetViewportElement(&svgElem); cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, svgElem.GetWidth().GetAnimVal()/scaleX, svgElem.GetHeight().GetAnimVal()/scaleY); cairo_t* cr = cairo_create(surface); wxSVGMatrix maskMatrix; maskMatrix = maskMatrix.Translate(x, y).ScaleNonUniform(scaleX, scaleY).Inverse(); DrawMask(cr, maskElem, maskMatrix, style, svgElem); cairo_mask_surface(m_cr, surface, 0, 0); cairo_destroy(cr); cairo_surface_destroy(surface); } } else { cairo_paint_with_alpha(m_cr, style.GetOpacity()); } cairo_new_path(m_cr); // clean up cairo_restore(m_cr); }
void wxSVGCanvasCairo::DrawMask(cairo_t* cr, wxSVGElement* maskElem, const wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { SetMatrix(cr, matrix); wxSVGElement* elem = (wxSVGElement*) (maskElem->GetFirstChild()); while (elem != NULL) { elem->SetOwnerSVGElement(maskElem->GetOwnerSVGElement()); elem->SetViewportElement(maskElem->GetViewportElement()); wxSVGDocument* doc = (wxSVGDocument*) elem->GetOwnerDocument(); wxSVGCanvasItem* canvasItem = NULL; wxCSSStyleDeclaration resStyle = style; switch (elem->GetDtd()) { case wxSVG_G_ELEMENT: { wxSVGGElement* gElement = (wxSVGGElement*) elem; if (gElement->GetVisibility() == wxCSS_VALUE_HIDDEN) break; resStyle.Add(((wxSVGGElement*) elem)->GetStyle()); DrawMask(cr, elem, matrix, resStyle, svgElem); break; } case wxSVG_LINE_ELEMENT: { wxSVGLineElement* element = (wxSVGLineElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_POLYLINE_ELEMENT: { wxSVGPolylineElement* element = (wxSVGPolylineElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_POLYGON_ELEMENT: { wxSVGPolygonElement* element = (wxSVGPolygonElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_RECT_ELEMENT: { wxSVGRectElement* element = (wxSVGRectElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_CIRCLE_ELEMENT: { wxSVGCircleElement* element = (wxSVGCircleElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_ELLIPSE_ELEMENT: { wxSVGEllipseElement* element = (wxSVGEllipseElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_PATH_ELEMENT: { wxSVGPathElement* element = (wxSVGPathElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; canvasItem = doc->GetCanvas()->CreateItem(element); resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); break; } case wxSVG_USE_ELEMENT: { wxSVGUseElement* element = (wxSVGUseElement*) elem; if (element->GetVisibility() == wxCSS_VALUE_HIDDEN) break; resStyle.Add(element->GetStyle()); resStyle.Add(element->GetAnimStyle()); // get ref element wxString href = element->GetHref(); if (href.length() == 0 || href.GetChar(0) != wxT('#')) break; href.Remove(0, 1); wxSVGElement* refElem = (wxSVGElement*) maskElem->GetOwnerSVGElement()->GetElementById(href); if (!refElem) break; // create shadow tree wxSVGGElement* gElem = new wxSVGGElement(); gElem->SetOwnerDocument(elem->GetOwnerDocument()); gElem->SetOwnerSVGElement(maskElem->GetOwnerSVGElement()); gElem->SetViewportElement(maskElem->GetViewportElement()); gElem->SetStyle(element->GetStyle()); if (element->GetX().GetAnimVal().GetUnitType() != wxSVG_LENGTHTYPE_UNKNOWN) gElem->Translate(element->GetX().GetAnimVal(), element->GetY().GetAnimVal()); if (refElem->GetDtd() == wxSVG_SYMBOL_ELEMENT || refElem->GetDtd() == wxSVG_SVG_ELEMENT) { wxSVGSVGElement* svgElem; if (refElem->GetDtd() == wxSVG_SVG_ELEMENT) svgElem = (wxSVGSVGElement*) refElem->CloneNode(); else { svgElem = new wxSVGSVGElement(); wxSvgXmlElement* child = refElem->GetChildren(); while (child) { svgElem->AddChild(child->CloneNode()); child = child->GetNext(); } svgElem->SetViewBox(((wxSVGSymbolElement*) refElem)->GetViewBox()); svgElem->SetPreserveAspectRatio(((wxSVGSymbolElement*) refElem)->GetPreserveAspectRatio()); } if (element->GetWidth().GetAnimVal().GetUnitType() != wxSVG_LENGTHTYPE_UNKNOWN) svgElem->SetWidth(element->GetWidth().GetAnimVal()); if (element->GetHeight().GetAnimVal().GetUnitType() != wxSVG_LENGTHTYPE_UNKNOWN) svgElem->SetHeight(element->GetHeight().GetAnimVal()); gElem->AddChild(svgElem); } else gElem->AddChild(refElem->CloneNode()); // render DrawMask(cr, gElem, matrix, resStyle, svgElem); // delete shadow tree delete gElem; break; } default: break; } if (canvasItem != NULL) { DrawPath(cr, ((wxSVGCanvasPathCairo&) *canvasItem), matrix, resStyle, svgElem); delete canvasItem; } elem = (wxSVGElement*) elem->GetNextSibling(); } }