• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KHTML

  • sources
  • kde-4.12
  • kdelibs
  • khtml
  • svg
SVGSVGElement.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
3  2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4  2007 Apple Inc. All rights reserved.
5 
6  This file is part of the KDE project
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #include "config.h"
25 #include <wtf/Platform.h>
26 
27 #if ENABLE(SVG)
28 #include "SVGSVGElement.h"
29 
30 #include "AffineTransform.h"
31 /*#include "CSSHelper.h"*/
32 #include "css/csshelper.h"
33 /*#include "CSSPropertyNames.h"*/
34 #include "Document.h"
35 //#include "EventListener.h"
36 #include "dom/dom2_events.h"
37 /*#include "EventNames.h"*/
38 #include "FloatConversion.h"
39 #include "FloatRect.h"
40 /*#include "Frame.h"
41 #include "HTMLNames.h"
42 #include "RenderSVGViewportContainer.h"*/
43 #include "RenderSVGRoot.h"
44 #include "SVGAngle.h"
45 #include "SVGLength.h"
46 #include "SVGNames.h"
47 #include "SVGPreserveAspectRatio.h"
48 #include "SVGTransform.h"
49 #include "SVGTransformList.h"
50 /*#include "SVGViewElement.h"*/
51 #include "SVGViewSpec.h"
52 /*#include "SVGZoomEvent.h"
53 #include "SelectionController.h"
54 #include "SMILTimeContainer.h"*/
55 #include "khtml_part.h"
56 
57 namespace WebCore {
58 
59 /*using namespace HTMLNames;
60 using namespace EventNames;*/
61 using namespace SVGNames;
62 
63 SVGSVGElement::SVGSVGElement(const QualifiedName& tagName, Document* doc)
64  : SVGStyledLocatableElement(tagName, doc)
65  , SVGTests()
66  , SVGLangSpace()
67  , SVGExternalResourcesRequired()
68  , SVGFitToViewBox()
69  , SVGZoomAndPan()
70  , m_x(this, LengthModeWidth)
71  , m_y(this, LengthModeHeight)
72  , m_width(this, LengthModeWidth)
73  , m_height(this, LengthModeHeight)
74  , m_useCurrentView(false)
75  /*, m_timeContainer(SMILTimeContainer::create(this))
76  , m_viewSpec(0)*/
77 {
78  setWidthBaseValue(SVGLength(this, LengthModeWidth, "100%"));
79  setHeightBaseValue(SVGLength(this, LengthModeHeight, "100%"));
80  //doc->registerForCacheCallbacks(this);
81 }
82 
83 SVGSVGElement::~SVGSVGElement()
84 {
85  /*document()->unregisterForCacheCallbacks(this);
86  // There are cases where removedFromDocument() is not called.
87  // see ContainerNode::removeAllChildren, called by it's destructor.
88  document()->accessSVGExtensions()->removeTimeContainer(this);*/
89 }
90 
91 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x)
92 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
93 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
94 ANIMATED_PROPERTY_DEFINITIONS(SVGSVGElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
95 
96 DOMString SVGSVGElement::contentScriptType() const
97 {
98  static const DOMString defaultValue("text/ecmascript");
99  DOMString n = getAttribute(contentScriptTypeAttr);
100  return n.isNull() ? defaultValue : n;
101 }
102 
103 void SVGSVGElement::setContentScriptType(const DOMString& type)
104 {
105  setAttribute(SVGNames::contentScriptTypeAttr, type);
106 }
107 
108 DOMString SVGSVGElement::contentStyleType() const
109 {
110  static const DOMString defaultValue("text/css");
111  const DOMString n = getAttribute(contentStyleTypeAttr);
112  return n.isNull() ? defaultValue : n;
113 }
114 
115 void SVGSVGElement::setContentStyleType(const DOMString& type)
116 {
117  setAttribute(SVGNames::contentStyleTypeAttr, type);
118 }
119 
120 bool SVGSVGElement::hasSetContainerSize() const
121 {
122  // For now, we interpret % dimensions only if we're a top-level SVG element nested inside
123  // an another part. ### might even want to check if we're the documentElement; this
124  // will also need changes with <img> handling
125  return isOutermostSVG() && document()->part()->parentPart();
126 }
127 
128 IntSize SVGSVGElement::containerSize() const
129 {
130  if (KHTMLView* v = document()->view())
131  return IntSize(v->visibleWidth(), v->visibleHeight());
132  else
133  return IntSize(300, 150);
134 }
135 
136 FloatRect SVGSVGElement::viewport() const
137 {
138  double _x = 0.0;
139  double _y = 0.0;
140  if (!isOutermostSVG()) {
141  _x = x().value();
142  _y = y().value();
143  }
144  float w = width().value();
145  float h = height().value();
146  AffineTransform viewBox = viewBoxToViewTransform(w, h);
147  double wDouble = w;
148  double hDouble = h;
149  viewBox.map(_x, _y, &_x, &_y);
150  viewBox.map(w, h, &wDouble, &hDouble);
151  return FloatRect::narrowPrecision(_x, _y, wDouble, hDouble);
152 }
153 
154 int SVGSVGElement::relativeWidthValue() const
155 {
156  SVGLength w = width();
157  if (w.unitType() != LengthTypePercentage)
158  return 0;
159 
160  return static_cast<int>(w.valueAsPercentage() * containerSize().width());
161 }
162 
163 int SVGSVGElement::relativeHeightValue() const
164 {
165  SVGLength h = height();
166  if (h.unitType() != LengthTypePercentage)
167  return 0;
168 
169  return static_cast<int>(h.valueAsPercentage() * containerSize().height());
170 }
171 
172 float SVGSVGElement::pixelUnitToMillimeterX() const
173 {
174  // 2.54 / cssPixelsPerInch gives CM.
175  return (2.54f / cssPixelsPerInch) * 10.0f;
176 }
177 
178 float SVGSVGElement::pixelUnitToMillimeterY() const
179 {
180  // 2.54 / cssPixelsPerInch gives CM.
181  return (2.54f / cssPixelsPerInch) * 10.0f;
182 }
183 
184 float SVGSVGElement::screenPixelToMillimeterX() const
185 {
186  return pixelUnitToMillimeterX();
187 }
188 
189 float SVGSVGElement::screenPixelToMillimeterY() const
190 {
191  return pixelUnitToMillimeterY();
192 }
193 
194 bool SVGSVGElement::useCurrentView() const
195 {
196  return m_useCurrentView;
197 }
198 
199 void SVGSVGElement::setUseCurrentView(bool currentView)
200 {
201  m_useCurrentView = currentView;
202 }
203 
204 SVGViewSpec* SVGSVGElement::currentView() const
205 {
206  if (!m_viewSpec)
207  m_viewSpec.set(new SVGViewSpec(this));
208 
209  return m_viewSpec.get();
210 }
211 
212 float SVGSVGElement::currentScale() const
213 {
214  /*if (document() && document()->frame())
215  return document()->frame()->zoomFactor();*/
216  return 1.0f;
217 }
218 
219 void SVGSVGElement::setCurrentScale(float scale)
220 {
221  Q_UNUSED(scale);
222  /*if (document() && document()->frame())
223  document()->frame()->setZoomFactor(scale, true);*/
224 }
225 
226 FloatPoint SVGSVGElement::currentTranslate() const
227 {
228  return m_translation;
229 }
230 
231 void SVGSVGElement::setCurrentTranslate(const FloatPoint &translation)
232 {
233  m_translation = translation;
234  if (parentNode() == document() && document()->renderer())
235  document()->renderer()->repaint();
236 }
237 
238 void SVGSVGElement::addSVGWindowEventListener(const AtomicString& eventType, const Attribute* attr)
239 {
240  Q_UNUSED(eventType);
241  // FIXME: None of these should be window events long term.
242  // Once we propertly support SVGLoad, etc.
243  RefPtr<EventListener> listener = document()->accessSVGExtensions()->
244  createSVGEventListener(attr->localName().string(), attr->value(), this);
245  //document()->setHTMLWindowEventListener(eventType, listener.release());
246 }
247 
248 void SVGSVGElement::parseMappedAttribute(MappedAttribute* attr)
249 {
250  kDebug() << "parse attribute: " << attr->localName() << attr->value() << endl;
251  if (!nearestViewportElement()) {
252  // Only handle events if we're the outermost <svg> element
253  /*if (attr->name() == onunloadAttr)
254  addSVGWindowEventListener(unloadEvent, attr);
255  else if (attr->name() == onabortAttr)
256  addSVGWindowEventListener(abortEvent, attr);
257  else if (attr->name() == onerrorAttr)
258  addSVGWindowEventListener(errorEvent, attr);
259  else if (attr->name() == onresizeAttr)
260  addSVGWindowEventListener(resizeEvent, attr);
261  else if (attr->name() == onscrollAttr)
262  addSVGWindowEventListener(scrollEvent, attr);
263  else if (attr->name() == SVGNames::onzoomAttr)
264  addSVGWindowEventListener(zoomEvent, attr);*/
265  }
266  if (attr->name() == SVGNames::xAttr)
267  setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
268  else if (attr->name() == SVGNames::yAttr)
269  setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
270  else if (attr->name() == SVGNames::widthAttr) {
271  kDebug() << "set width" << attr->value() << endl;
272  setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
273  addCSSProperty(attr, CSSPropertyWidth, attr->value());
274  /*if (width().value() < 0.0)
275  document()->accessSVGExtensions()->reportError("A negative value for svg attribute <width> is not allowed");*/
276  } else if (attr->name() == SVGNames::heightAttr) {
277  kDebug() << "set height" << attr->value() << endl;
278  setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
279  addCSSProperty(attr, CSSPropertyHeight, attr->value());
280  /*if (height().value() < 0.0)
281  document()->accessSVGExtensions()->reportError("A negative value for svg attribute <height> is not allowed");*/
282  } else {
283  /*if (SVGTests::parseMappedAttribute(attr))
284  return;
285  if (SVGLangSpace::parseMappedAttribute(attr))
286  return;
287  if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
288  return;
289  if (SVGFitToViewBox::parseMappedAttribute(attr))
290  return;
291  if (SVGZoomAndPan::parseMappedAttribute(attr))
292  return;*/
293 
294  SVGStyledLocatableElement::parseMappedAttribute(attr);
295  }
296 }
297 
298 void SVGSVGElement::svgAttributeChanged(const QualifiedName& attrName)
299 {
300  SVGStyledElement::svgAttributeChanged(attrName);
301 
302  if (!renderer())
303  return;
304 
305  /*if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
306  attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
307  SVGTests::isKnownAttribute(attrName) ||
308  SVGLangSpace::isKnownAttribute(attrName) ||
309  SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
310  SVGFitToViewBox::isKnownAttribute(attrName) ||
311  SVGZoomAndPan::isKnownAttribute(attrName) ||
312  SVGStyledLocatableElement::isKnownAttribute(attrName))
313  renderer()->setNeedsLayout(true);*/
314 }
315 
316 unsigned long SVGSVGElement::suspendRedraw(unsigned long /* max_wait_milliseconds */)
317 {
318  // FIXME: Implement me (see bug 11275)
319  return 0;
320 }
321 
322 void SVGSVGElement::unsuspendRedraw(unsigned long /* suspend_handle_id */, ExceptionCode& /*ec*/)
323 {
324  // if suspend_handle_id is not found, throw exception
325  // FIXME: Implement me (see bug 11275)
326 }
327 
328 void SVGSVGElement::unsuspendRedrawAll()
329 {
330  // FIXME: Implement me (see bug 11275)
331 }
332 
333 void SVGSVGElement::forceRedraw()
334 {
335  // FIXME: Implement me (see bug 11275)
336 }
337 
338 DOM::NodeListImpl* SVGSVGElement::getIntersectionList(const FloatRect& rect, SVGElement*)
339 {
340  Q_UNUSED(rect);
341  // FIXME: Implement me (see bug 11274)
342  return 0;
343 }
344 
345 DOM::NodeListImpl* SVGSVGElement::getEnclosureList(const FloatRect& rect, SVGElement*)
346 {
347  Q_UNUSED(rect);
348  // FIXME: Implement me (see bug 11274)
349  return 0;
350 }
351 
352 bool SVGSVGElement::checkIntersection(SVGElement* element, const FloatRect& rect)
353 {
354  Q_UNUSED(element);
355  // TODO : take into account pointer-events?
356  // FIXME: Why is element ignored??
357  // FIXME: Implement me (see bug 11274)
358  return rect.intersects(getBBox());
359 }
360 
361 bool SVGSVGElement::checkEnclosure(SVGElement* element, const FloatRect& rect)
362 {
363  Q_UNUSED(element);
364  // TODO : take into account pointer-events?
365  // FIXME: Why is element ignored??
366  // FIXME: Implement me (see bug 11274)
367  return rect.contains(getBBox());
368 }
369 
370 void SVGSVGElement::deselectAll()
371 {
372  //document()->frame()->selectionController()->clear();
373 }
374 
375 float SVGSVGElement::createSVGNumber()
376 {
377  return 0.0f;
378 }
379 
380 SVGLength SVGSVGElement::createSVGLength()
381 {
382  return SVGLength();
383 }
384 
385 SVGAngle* SVGSVGElement::createSVGAngle()
386 {
387  return new SVGAngle();
388 }
389 
390 FloatPoint SVGSVGElement::createSVGPoint()
391 {
392  return FloatPoint();
393 }
394 
395 AffineTransform SVGSVGElement::createSVGMatrix()
396 {
397  return AffineTransform();
398 }
399 
400 FloatRect SVGSVGElement::createSVGRect()
401 {
402  return FloatRect();
403 }
404 
405 SVGTransform SVGSVGElement::createSVGTransform()
406 {
407  return SVGTransform();
408 }
409 
410 SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const AffineTransform& matrix)
411 {
412  return SVGTransform(matrix);
413 }
414 
415 AffineTransform SVGSVGElement::getCTM() const
416 {
417  AffineTransform mat;
418  if (!isOutermostSVG())
419  mat.translate(x().value(), y().value());
420 
421  if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
422  AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value());
423  mat = viewBox * mat;
424  }
425 
426  return mat;
427 }
428 
429 AffineTransform SVGSVGElement::getScreenCTM() const
430 {
431  /*document()->updateLayoutIgnorePendingStylesheets();
432  float rootX = 0.0f;
433  float rootY = 0.0f;
434 
435  if (RenderObject* renderer = this->renderer()) {
436  renderer = renderer->parent();
437  if (isOutermostSVG()) {
438  int tx = 0;
439  int ty = 0;
440  if (renderer)
441  renderer->absolutePosition(tx, ty, true);
442  rootX += tx;
443  rootY += ty;
444  } else {
445  rootX += x().value();
446  rootY += y().value();
447  }
448  }
449 
450  AffineTransform mat = SVGStyledLocatableElement::getScreenCTM();
451  mat.translate(rootX, rootY);
452 
453  if (attributes()->getNamedItem(SVGNames::viewBoxAttr)) {
454  AffineTransform viewBox = viewBoxToViewTransform(width().value(), height().value());
455  mat = viewBox * mat;
456  }
457 
458  return mat;*/
459  ASSERT(false);
460  return AffineTransform();
461 }
462 
463 RenderObject* SVGSVGElement::createRenderer(RenderArena* arena, RenderStyle*)
464 {
465  kDebug() << "create RenderSVGRoot from <svg> element" << endl;
466  return new (arena) RenderSVGRoot(this);
467  /*if (isOutermostSVG())
468  return new (arena) RenderSVGRoot(this);
469  else
470  return new (arena) RenderSVGViewportContainer(this);*/
471 }
472 
473 void SVGSVGElement::insertedIntoDocument()
474 {
475  document()->accessSVGExtensions()->addTimeContainer(this);
476  SVGStyledLocatableElement::insertedIntoDocument();
477 }
478 
479 void SVGSVGElement::removedFromDocument()
480 {
481  document()->accessSVGExtensions()->removeTimeContainer(this);
482  SVGStyledLocatableElement::removedFromDocument();
483 }
484 
485 void SVGSVGElement::pauseAnimations()
486 {
487  /*if (!m_timeContainer->isPaused())
488  m_timeContainer->pause();*/
489 }
490 
491 void SVGSVGElement::unpauseAnimations()
492 {
493  /*if (m_timeContainer->isPaused())
494  m_timeContainer->resume();*/
495 }
496 
497 bool SVGSVGElement::animationsPaused() const
498 {
499  //return m_timeContainer->isPaused();
500  ASSERT(false);
501  return false;
502 }
503 
504 float SVGSVGElement::getCurrentTime() const
505 {
506  //return narrowPrecisionToFloat(m_timeContainer->elapsed().value());
507  ASSERT(false);
508  return 0.0;
509 }
510 
511 void SVGSVGElement::setCurrentTime(float /* seconds */)
512 {
513  // FIXME: Implement me, bug 12073
514 }
515 
516 bool SVGSVGElement::hasRelativeValues() const
517 {
518  return (x().isRelative() || width().isRelative() ||
519  y().isRelative() || height().isRelative());
520 }
521 
522 bool SVGSVGElement::isOutermostSVG() const
523 {
524  // This is true whenever this is the outermost SVG, even if there are HTML elements outside it
525  return !parentNode()->isSVGElement();
526 }
527 
528 AffineTransform SVGSVGElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
529 {
530  FloatRect viewBoxRect;
531  if (useCurrentView()) {
532  if (currentView()) // what if we should use it but it is not set?
533  viewBoxRect = currentView()->viewBox();
534  } else
535  viewBoxRect = viewBox();
536  if (!viewBoxRect.width() || !viewBoxRect.height())
537  return AffineTransform();
538 
539  AffineTransform ctm = preserveAspectRatio()->getCTM(viewBoxRect.x(),
540  viewBoxRect.y(), viewBoxRect.width(), viewBoxRect.height(),
541  0, 0, viewWidth, viewHeight);
542 
543  if (useCurrentView() && currentView())
544  return currentView()->transform()->concatenate().matrix() * ctm;
545 
546  return ctm;
547 }
548 
549 /*void SVGSVGElement::inheritViewAttributes(SVGViewElement* viewElement)
550 {
551  setUseCurrentView(true);
552  if (viewElement->hasAttribute(SVGNames::viewBoxAttr))
553  currentView()->setViewBox(viewElement->viewBox());
554  else
555  currentView()->setViewBox(viewBox());
556  if (viewElement->hasAttribute(SVGNames::preserveAspectRatioAttr)) {
557  currentView()->preserveAspectRatio()->setAlign(viewElement->preserveAspectRatio()->align());
558  currentView()->preserveAspectRatio()->setMeetOrSlice(viewElement->preserveAspectRatio()->meetOrSlice());
559  } else {
560  currentView()->preserveAspectRatio()->setAlign(preserveAspectRatio()->align());
561  currentView()->preserveAspectRatio()->setMeetOrSlice(preserveAspectRatio()->meetOrSlice());
562  }
563  if (viewElement->hasAttribute(SVGNames::zoomAndPanAttr))
564  currentView()->setZoomAndPan(viewElement->zoomAndPan());
565  renderer()->setNeedsLayout(true);
566 }*/
567 
568 void SVGSVGElement::willSaveToCache()
569 {
570  //pauseAnimations();
571 }
572 
573 void SVGSVGElement::willRestoreFromCache()
574 {
575  //unpauseAnimations();
576 }
577 
578 // KHTML stuff
579 quint32 SVGSVGElement::id() const { return SVGNames::svgTag.id(); }
580 
581 }
582 
583 #endif // ENABLE(SVG)
584 
585 // vim:ts=4:noet
SVGViewSpec.h
WebCore::SVGNames::widthAttr
DOM::QualifiedName widthAttr
Definition: SVGNames.cpp:334
SVGAngle.h
khtml_part.h
DOM::QualifiedName::id
unsigned id() const
Definition: QualifiedName.cpp:90
WebCore::SVGNames::svgTag
DOM::QualifiedName svgTag
Definition: SVGNames.cpp:91
KHTMLView
Renders and displays HTML in a QScrollArea.
Definition: khtmlview.h:92
quint32
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
SVGLength.h
SVGSVGElement.h
AffineTransform.h
SVGPreserveAspectRatio.h
FloatConversion.h
WebCore::SVGNames::viewBoxAttr
DOM::QualifiedName viewBoxAttr
Definition: SVGNames.cpp:331
WebCore::SVGNames::yAttr
DOM::QualifiedName yAttr
Definition: SVGNames.cpp:343
WebCore::SVGNames::heightAttr
DOM::QualifiedName heightAttr
Definition: SVGNames.cpp:186
SVGNames.h
WebCore::SVGNames::contentStyleTypeAttr
DOM::QualifiedName contentStyleTypeAttr
Definition: SVGNames.cpp:133
SVGTransform.h
FloatRect.h
dom2_events.h
WebCore::SVGNames::contentScriptTypeAttr
DOM::QualifiedName contentScriptTypeAttr
Definition: SVGNames.cpp:132
SVGTransformList.h
WebCore::SVGNames::xAttr
DOM::QualifiedName xAttr
Definition: SVGNames.cpp:338
defaultValue
QString defaultValue(const QString &t)
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:51:22 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal