diff --git a/src/declarative/items/qquicktextedit.cpp b/src/declarative/items/qquicktextedit.cpp
index 2e799200e65a127c68caa120f36e07c2cec13605..51231e17de5226be7bfffab2879a35c553c9deb9 100644
--- a/src/declarative/items/qquicktextedit.cpp
+++ b/src/declarative/items/qquicktextedit.cpp
@@ -635,6 +635,25 @@ int QQuickTextEdit::lineCount() const
     return d->lineCount;
 }
 
+/*!
+    \qmlproperty int QtQuick2::TextEdit::length
+
+    Returns the total number of plain text characters in the TextEdit item.
+
+    As this number doesn't include any formatting markup it may not be the same as the
+    length of the string returned by the \l text property.
+
+    This property can be faster than querying the length the \l text property as it doesn't
+    require any copying or conversion of the TextEdit's internal string data.
+*/
+
+int QQuickTextEdit::length() const
+{
+    Q_D(const QQuickTextEdit);
+    // QTextDocument::characterCount() includes the terminating null character.
+    return qMax(0, d->document->characterCount() - 1);
+}
+
 /*!
     \qmlproperty real QtQuick2::TextEdit::paintedWidth
 
diff --git a/src/declarative/items/qquicktextedit_p.h b/src/declarative/items/qquicktextedit_p.h
index 66b68ffd85257d155a22868f55036b4106f2bba4..25988959f6bf5a7ad8707a79035484dda07bd5fa 100644
--- a/src/declarative/items/qquicktextedit_p.h
+++ b/src/declarative/items/qquicktextedit_p.h
@@ -73,6 +73,7 @@ class Q_AUTOTEST_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem
     Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged)
     Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged)
     Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged)
+    Q_PROPERTY(int length READ length NOTIFY textChanged)
     Q_PROPERTY(qreal paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
     Q_PROPERTY(qreal paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
     Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)
@@ -161,6 +162,8 @@ public:
 
     int lineCount() const;
 
+    int length() const;
+
     bool isCursorVisible() const;
     void setCursorVisible(bool on);
 
diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
index e348cae7e67b71c2912e6ea968110c75ca420835..6bcad83c522eed1ffb70a9a83da065f4ee8de076 100644
--- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
@@ -314,6 +314,7 @@ void tst_qquicktextedit::text()
 
         QVERIFY(textEditObject != 0);
         QCOMPARE(textEditObject->text(), QString(""));
+        QCOMPARE(textEditObject->length(), 0);
     }
 
     for (int i = 0; i < standard.size(); i++)
@@ -325,6 +326,7 @@ void tst_qquicktextedit::text()
 
         QVERIFY(textEditObject != 0);
         QCOMPARE(textEditObject->text(), standard.at(i));
+        QCOMPARE(textEditObject->length(), standard.at(i).length());
     }
 
     for (int i = 0; i < richText.size(); i++)
@@ -341,6 +343,9 @@ void tst_qquicktextedit::text()
         actual.replace(QRegExp("(<[^>]*>)+"),"<>");
         expected.replace(QRegExp("(<[^>]*>)+"),"<>");
         QCOMPARE(actual.simplified(),expected.simplified());
+
+        expected.replace("<>", " ");
+        QCOMPARE(textEditObject->length(), expected.simplified().length());
     }
 }
 
@@ -2738,7 +2743,9 @@ void tst_qquicktextedit::insert()
         QCOMPARE(textEdit->getText(0, expectedText.length()), expectedText);
     } else {
         QCOMPARE(textEdit->text(), expectedText);
+
     }
+    QCOMPARE(textEdit->length(), expectedText.length());
 
     QCOMPARE(textEdit->selectionStart(), expectedSelectionStart);
     QCOMPARE(textEdit->selectionEnd(), expectedSelectionEnd);
@@ -2751,7 +2758,7 @@ void tst_qquicktextedit::insert()
     QEXPECT_FAIL("into reversed selection", "selectionChanged signal isn't emitted on edits within selection", Continue);
     QCOMPARE(selectionSpy.count() > 0, selectionChanged);
     QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
-    QEXPECT_FAIL("into reversed selection", "yeah I don't know", Continue);
+    QEXPECT_FAIL("into reversed selection", "selectionEndChanged signal not emitted", Continue);
     QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
     QCOMPARE(textSpy.count() > 0, text != expectedText);
     QCOMPARE(cursorPositionSpy.count() > 0, cursorPositionChanged);
@@ -2982,6 +2989,7 @@ void tst_qquicktextedit::remove()
     } else {
         QCOMPARE(textEdit->text(), expectedText);
     }
+    QCOMPARE(textEdit->length(), expectedText.length());
 
     if (selectionStart > selectionEnd)  //
         qSwap(selectionStart, selectionEnd);