diff options
Diffstat (limited to 'src/quick/items/context2d/qquickcontext2d.cpp')
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d.cpp | 192 |
1 files changed, 164 insertions, 28 deletions
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 2c115f4d3c..32336b5baf 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -563,6 +563,8 @@ struct QQuickJSContext2D : public QV4::Object static QV4::ReturnedValue method_set_lineWidth(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_get_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_set_miterLimit(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_get_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_set_shadowBlur(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); @@ -596,7 +598,7 @@ public: static QV4::Heap::QQuickJSContext2DPrototype *create(QV4::ExecutionEngine *engine) { QV4::Scope scope(engine); - QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocObject<QQuickJSContext2DPrototype>()); + QV4::Scoped<QQuickJSContext2DPrototype> o(scope, engine->memoryManager->allocate<QQuickJSContext2DPrototype>()); o->defineDefaultProperty(QStringLiteral("quadraticCurveTo"), method_quadraticCurveTo, 0); o->defineDefaultProperty(QStringLiteral("restore"), method_restore, 0); @@ -641,6 +643,8 @@ public: o->defineDefaultProperty(QStringLiteral("createLinearGradient"), method_createLinearGradient, 0); o->defineDefaultProperty(QStringLiteral("strokeRect"), method_strokeRect, 0); o->defineDefaultProperty(QStringLiteral("closePath"), method_closePath, 0); + o->defineDefaultProperty(QStringLiteral("setLineDash"), method_setLineDash, 0); + o->defineDefaultProperty(QStringLiteral("getLineDash"), method_getLineDash, 0); o->defineAccessorProperty(QStringLiteral("canvas"), QQuickJSContext2DPrototype::method_get_canvas, nullptr); return o->d(); @@ -690,6 +694,8 @@ public: static QV4::ReturnedValue method_createImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_getImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); static QV4::ReturnedValue method_putImageData(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); }; @@ -908,8 +914,8 @@ struct QQuickJSContext2DPixelData : public QV4::Object V4_OBJECT2(QQuickJSContext2DPixelData, QV4::Object) V4_NEEDS_DESTROY - static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty); - static bool putIndexed(QV4::Managed *m, uint index, const QV4::Value &value); + static QV4::ReturnedValue virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty); + static bool virtualPut(QV4::Managed *m, QV4::PropertyKey id, const QV4::Value &value, Value *receiver); static QV4::ReturnedValue proto_get_length(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc); }; @@ -938,7 +944,7 @@ struct QQuickJSContext2DImageData : public QV4::Object void QV4::Heap::QQuickJSContext2DImageData::init() { Object::init(); - pixelData = QV4::Primitive::undefinedValue(); + pixelData = QV4::Value::undefinedValue(); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); @@ -954,19 +960,19 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE { QV4::Scope scope(v4); QQuickContext2DEngineData *ed = engineData(scope.engine); - QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DPixelData>()); + QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DPixelData>()); QV4::ScopedObject p(scope, ed->pixelArrayProto.value()); - pixelData->setPrototype(p); + pixelData->setPrototypeOf(p); if (image.isNull()) { *pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); pixelData->d()->image->fill(0x00000000); } else { - Q_ASSERT(image.width()== qRound(w * image.devicePixelRatio()) && image.height() == qRound(h * image.devicePixelRatio())); + Q_ASSERT(image.width()== qRound(w * image.devicePixelRatioF()) && image.height() == qRound(h * image.devicePixelRatioF())); *pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); } - QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DImageData>()); + QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DImageData>()); imageData->d()->pixelData = pixelData.asReturnedValue(); return imageData.asReturnedValue(); } @@ -1406,7 +1412,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(const QV4::FunctionOb QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>()); CHECK_CONTEXT_SETTER(r) - QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Primitive::undefinedValue()); + QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue()); if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); @@ -1461,7 +1467,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(const QV4::FunctionObj QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>()); CHECK_CONTEXT_SETTER(r) - QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Primitive::undefinedValue()); + QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue()); if ((value->isString() && value->toQString() == QLatin1String("WindingFill")) || (value->isInt32() && value->integerValue() == Qt::WindingFill)) { @@ -1515,7 +1521,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(const QV4::Function QV4::Scoped<QQuickJSContext2D> r(scope, thisObject->as<QQuickJSContext2D>()); CHECK_CONTEXT_SETTER(r) - QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Primitive::undefinedValue()); + QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue()); if (value->as<Object>()) { QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>(); @@ -1582,9 +1588,9 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(const } QQuickContext2DEngineData *ed = engineData(scope.engine); - QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); + QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QLinearGradient(x0, y0, x1, y1); RETURN_RESULT(*gradient); } @@ -1634,9 +1640,9 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(const QQuickContext2DEngineData *ed = engineData(scope.engine); - QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); + QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r1, QPointF(x0, y0), r0); RETURN_RESULT(*gradient); } @@ -1678,9 +1684,9 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(cons QQuickContext2DEngineData *ed = engineData(scope.engine); - QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); + QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QConicalGradient(x, y, angle); RETURN_RESULT(*gradient); } @@ -1738,7 +1744,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(const QV4::F CHECK_CONTEXT(r) if (argc >= 2) { - QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); + QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QColor color = scope.engine->toVariant(argv[0], qMetaTypeId<QColor>()).value<QColor>(); if (color.isValid()) { @@ -1963,6 +1969,122 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(const QV4::FunctionO RETURN_UNDEFINED(); } +/*! + \qmlmethod array QtQuick::Context2D::getLineDash() + \since QtQuick 2.11 + Returns an array of qreals representing the dash pattern of the line. + + \sa setLineDash() + */ +QV4::ReturnedValue QQuickJSContext2DPrototype::method_getLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT(r) + + const QVector<qreal> pattern = r->d()->context->state.lineDash; + QV4::ScopedArrayObject array(scope, scope.engine->newArrayObject(pattern.size())); + array->arrayReserve(pattern.size()); + for (int i = 0; i < pattern.size(); i++) + array->put(i, QV4::Value::fromDouble(pattern[i])); + + array->setArrayLengthUnchecked(pattern.size()); + + RETURN_RESULT(*array); +} + +/*! + \qmlmethod QtQuick::Context2D::setLineDash(array pattern) + \since QtQuick 2.11 + Sets the dash pattern to the given pattern + + \a pattern a list of numbers that specifies distances to alternately draw a line and a gap. + + If the number of elements in the array is odd, the elements of the array get copied + and concatenated. For example, [5, 15, 25] will become [5, 15, 25, 5, 15, 25]. + + \table 100% + \row + \li \inlineimage qml-item-canvas-lineDash.png + \li + \code + var space = 4 + ctx.setLineDash([1, space, 3, space, 9, space, 27, space, 9, space]) + ... + ctx.stroke(); + \endcode + \endtable + + \sa setLineDash + */ +QV4::ReturnedValue QQuickJSContext2DPrototype::method_setLineDash(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT_SETTER(r) + + if (!argc) + RETURN_UNDEFINED(); + + QV4::ScopedArrayObject array(scope, argv[0]); + if (!array) + RETURN_UNDEFINED(); + + QV4::ScopedValue v(scope); + const uint arrayLength = array->getLength(); + QVector<qreal> dashes; + dashes.reserve(arrayLength); + for (uint i = 0; i < arrayLength; ++i) { + v = array->get(i); + const double number = v->toNumber(); + + if (!qt_is_finite(number) || (number < 0)) + RETURN_UNDEFINED(); + + dashes.append(v->toNumber()); + } + if (dashes.size() % 2 != 0) { + dashes += dashes; + } + + r->d()->context->state.lineDash = dashes; + r->d()->context->buffer()->setLineDash(dashes); + + RETURN_UNDEFINED(); +} + +/*! + \qmlproperty real QtQuick::Context2D::lineDashOffset + \since QtQuick 2.11 + + Holds the current line dash offset + The default line dash ofset value is 0 + */ +QV4::ReturnedValue QQuickJSContext2D::method_get_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT(r) + + RETURN_RESULT(QV4::Encode(r->d()->context->state.lineDashOffset)); +} + +QV4::ReturnedValue QQuickJSContext2D::method_set_lineDashOffset(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc) +{ + QV4::Scope scope(b); + QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); + CHECK_CONTEXT_SETTER(r) + + const qreal offset = argc ? argv[0].toNumber() : -1; + + if (qt_is_finite(offset) && offset != r->d()->context->state.lineDashOffset) { + r->d()->context->state.lineDashOffset = offset; + r->d()->context->buffer()->setLineDashOffset(offset); + } + RETURN_UNDEFINED(); +} + + // shadows /*! \qmlproperty real QtQuick::Context2D::shadowBlur @@ -2096,7 +2218,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(const QV4::FunctionObject QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); CHECK_CONTEXT_SETTER(r) - QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Primitive::undefinedValue()); + QV4::ScopedValue value(scope, argc ? argv[0] : QV4::Value::undefinedValue()); r->d()->context->beginPath(); QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, value); if (!!qobjectWrapper) { @@ -2593,7 +2715,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(const QV4::F bool pointInPath = false; if (argc >= 2) pointInPath = r->d()->context->isPointInPath(argv[0].toNumber(), argv[1].toNumber()); - RETURN_RESULT(QV4::Primitive::fromBoolean(pointInPath).asReturnedValue()); + RETURN_RESULT(QV4::Value::fromBoolean(pointInPath).asReturnedValue()); } QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawFocusRing(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *, int) @@ -2652,7 +2774,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_font(const QV4::FunctionObject QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); CHECK_CONTEXT_SETTER(r) - QV4::ScopedString s(scope, argc ? argv[0] : QV4::Primitive::undefinedValue(), QV4::ScopedString::Convert); + QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert); if (scope.engine->hasException) RETURN_UNDEFINED(); QFont font = qt_font_from_string(s->toQString(), r->d()->context->state.font); @@ -2704,7 +2826,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(const QV4::FunctionOb QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); CHECK_CONTEXT_SETTER(r) - QV4::ScopedString s(scope, argc ? argv[0] : QV4::Primitive::undefinedValue(), QV4::ScopedString::Convert); + QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert); if (scope.engine->hasException) RETURN_UNDEFINED(); QString textAlign = s->toQString(); @@ -2771,7 +2893,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(const QV4::Functio QV4::Scope scope(b); QV4::Scoped<QQuickJSContext2D> r(scope, *thisObject); CHECK_CONTEXT_SETTER(r) - QV4::ScopedString s(scope, argc ? argv[0] : QV4::Primitive::undefinedValue(), QV4::ScopedString::Convert); + QV4::ScopedString s(scope, argc ? argv[0] : QV4::Value::undefinedValue(), QV4::ScopedString::Convert); if (scope.engine->hasException) RETURN_UNDEFINED(); QString textBaseline = s->toQString(); @@ -2858,7 +2980,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(const QV4::Fun uint width = fm.width(argv[0].toQStringNoThrow()); QV4::ScopedObject tm(scope, scope.engine->newObject()); tm->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("width"))).getPointer(), - QV4::ScopedValue(scope, QV4::Primitive::fromDouble(width))); + QV4::ScopedValue(scope, QV4::Value::fromDouble(width))); RETURN_RESULT(*tm); } RETURN_UNDEFINED(); @@ -3130,8 +3252,12 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(const QV4::Funct RETURN_RESULT(QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4)); } -QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) +QV4::ReturnedValue QQuickJSContext2DPixelData::virtualGet(const QV4::Managed *m, QV4::PropertyKey id, const QV4::Value *receiver, bool *hasProperty) { + if (!id.isArrayIndex()) + return QV4::Object::virtualGet(m, id, receiver, hasProperty); + + uint index = id.asArrayIndex(); Q_ASSERT(m->as<QQuickJSContext2DPixelData>()); QV4::ExecutionEngine *v4 = static_cast<const QQuickJSContext2DPixelData *>(m)->engine(); QV4::Scope scope(v4); @@ -3156,19 +3282,24 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, return QV4::Encode(qAlpha(*pixel)); } } + if (hasProperty) *hasProperty = false; return QV4::Encode::undefined(); } -bool QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const QV4::Value &value) +bool QQuickJSContext2DPixelData::virtualPut(QV4::Managed *m, QV4::PropertyKey id, const QV4::Value &value, QV4::Value *receiver) { + if (!id.isArrayIndex()) + return Object::virtualPut(m, id, value, receiver); + Q_ASSERT(m->as<QQuickJSContext2DPixelData>()); QV4::ExecutionEngine *v4 = static_cast<QQuickJSContext2DPixelData *>(m)->engine(); QV4::Scope scope(v4); if (scope.hasException()) return false; + uint index = id.asArrayIndex(); QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m)); const int v = value.toInt32(); @@ -4303,6 +4434,7 @@ QQuickContext2DEngineData::QQuickContext2DEngineData(QV4::ExecutionEngine *v4) proto->defineAccessorProperty(QStringLiteral("lineWidth"), QQuickJSContext2D::method_get_lineWidth, QQuickJSContext2D::method_set_lineWidth); proto->defineAccessorProperty(QStringLiteral("textAlign"), QQuickJSContext2D::method_get_textAlign, QQuickJSContext2D::method_set_textAlign); proto->defineAccessorProperty(QStringLiteral("shadowBlur"), QQuickJSContext2D::method_get_shadowBlur, QQuickJSContext2D::method_set_shadowBlur); + proto->defineAccessorProperty(QStringLiteral("lineDashOffset"), QQuickJSContext2D::method_get_lineDashOffset, QQuickJSContext2D::method_set_lineDashOffset); contextPrototype = proto; proto = scope.engine->newObject(); @@ -4366,6 +4498,10 @@ void QQuickContext2D::popState() if (newState.shadowOffsetY != state.shadowOffsetY) buffer()->setShadowOffsetY(newState.shadowOffsetY); + + if (newState.lineDash != state.lineDash) + buffer()->setLineDash(newState.lineDash); + m_path = state.matrix.map(m_path); state = newState; m_path = state.matrix.inverted().map(m_path); @@ -4399,9 +4535,9 @@ void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine) QQuickContext2DEngineData *ed = engineData(engine); QV4::Scope scope(engine); - QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocObject<QQuickJSContext2D>()); + QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocate<QQuickJSContext2D>()); QV4::ScopedObject p(scope, ed->contextPrototype.value()); - wrapper->setPrototype(p); + wrapper->setPrototypeOf(p); wrapper->d()->context = this; m_v4value = wrapper; } |