1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "TextRecognition.h"
6 #include "mozilla/dom/Promise.h"
7 #include "mozilla/dom/ShadowRoot.h"
8 #include "mozilla/dom/Document.h"
9 #include "mozilla/dom/ContentChild.h"
10 #include "nsTextNode.h"
11 #include "imgIContainer.h"
13 using namespace mozilla::dom
;
15 namespace mozilla::widget
{
17 auto TextRecognition::FindText(imgIContainer
& aImage
,
18 const nsTArray
<nsCString
>& aLanguages
)
19 -> RefPtr
<NativePromise
> {
20 // TODO: Maybe decode async.
21 RefPtr
<gfx::SourceSurface
> surface
= aImage
.GetFrame(
22 imgIContainer::FRAME_CURRENT
,
23 imgIContainer::FLAG_SYNC_DECODE
| imgIContainer::FLAG_ASYNC_NOTIFY
);
24 if (NS_WARN_IF(!surface
)) {
25 return NativePromise::CreateAndReject("Failed to get surface"_ns
, __func__
);
27 RefPtr
<gfx::DataSourceSurface
> dataSurface
= surface
->GetDataSurface();
28 if (NS_WARN_IF(!dataSurface
)) {
29 return NativePromise::CreateAndReject("Failed to get data surface"_ns
,
32 return FindText(*dataSurface
, aLanguages
);
35 auto TextRecognition::FindText(gfx::DataSourceSurface
& aSurface
,
36 const nsTArray
<nsCString
>& aLanguages
)
37 -> RefPtr
<NativePromise
> {
38 if (XRE_IsContentProcess()) {
39 auto* contentChild
= ContentChild::GetSingleton();
40 auto image
= nsContentUtils::SurfaceToIPCImage(aSurface
);
42 return NativePromise::CreateAndReject("Failed to share data surface"_ns
,
45 auto promise
= MakeRefPtr
<NativePromise::Private
>(__func__
);
46 contentChild
->SendFindImageText(std::move(*image
), aLanguages
)
48 GetCurrentSerialEventTarget(), __func__
,
49 [promise
](TextRecognitionResultOrError
&& aResultOrError
) {
50 switch (aResultOrError
.type()) {
51 case TextRecognitionResultOrError::Type::TTextRecognitionResult
:
53 std::move(aResultOrError
.get_TextRecognitionResult()),
56 case TextRecognitionResultOrError::Type::TnsCString
:
57 promise
->Reject(std::move(aResultOrError
.get_nsCString()),
61 MOZ_ASSERT_UNREACHABLE("Unknown result?");
62 promise
->Reject("Unknown error"_ns
, __func__
);
66 [promise
](mozilla::ipc::ResponseRejectReason
) {
67 promise
->Reject("IPC rejection"_ns
, __func__
);
71 return DoFindText(aSurface
, aLanguages
);
74 void TextRecognition::FillShadow(ShadowRoot
& aShadow
,
75 const TextRecognitionResult
& aResult
) {
76 auto& doc
= *aShadow
.OwnerDoc();
77 RefPtr
<Element
> div
= doc
.CreateHTMLElement(nsGkAtoms::div
);
78 for (const auto& quad
: aResult
.quads()) {
79 RefPtr
<Element
> span
= doc
.CreateHTMLElement(nsGkAtoms::span
);
80 // TODO: We probably want to position them here and so on. For now, expose
81 // the data as attributes so that it's easy to play with the returned values
85 for (const auto& point
: quad
.points()) {
86 points
.AppendFloat(point
.x
);
88 points
.AppendFloat(point
.y
);
92 span
->SetAttribute(u
"data-points"_ns
, points
, IgnoreErrors());
93 nsAutoString confidence
;
94 confidence
.AppendFloat(quad
.confidence());
95 span
->SetAttribute(u
"data-confidence"_ns
, confidence
, IgnoreErrors());
99 RefPtr
<nsTextNode
> text
= doc
.CreateTextNode(quad
.string());
100 span
->AppendChildTo(text
, true, IgnoreErrors());
102 div
->AppendChildTo(span
, true, IgnoreErrors());
104 aShadow
.AppendChildTo(div
, true, IgnoreErrors());
108 auto TextRecognition::DoFindText(gfx::DataSourceSurface
&,
109 const nsTArray
<nsCString
>&)
110 -> RefPtr
<NativePromise
> {
111 MOZ_RELEASE_ASSERT(XRE_IsParentProcess(),
112 "This should only run in the parent process");
113 return NativePromise::CreateAndReject("Text recognition not available"_ns
,
118 bool TextRecognition::IsSupported() {
126 } // namespace mozilla::widget