1 /**
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // #define LOG_NDEBUG 0
18 #pragma once
19 
20 #include "BackgroundExecutor.h"
21 
22 #pragma clang diagnostic push
23 #pragma clang diagnostic ignored "-Wconversion"
24 #include <SkCanvas.h>
25 #include <SkPaint.h>
26 #pragma clang diagnostic pop
27 
28 #include <gui/SurfaceComposerClient.h>
29 #include <utils/StrongPointer.h>
30 
31 namespace android {
32 
33 inline constexpr int kDigitWidth = 64;
34 inline constexpr int kDigitHeight = 100;
35 inline constexpr int kDigitSpace = 16;
36 
37 // HdrSdrRatioOverlay re-uses this value though it doesn't really need such amount buffer.
38 // for output good-looking and code conciseness.
39 inline constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1;
40 inline constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace;
41 inline constexpr int kBufferHeight = kDigitHeight;
42 
43 class SurfaceControl;
44 
45 // Helper class to delete the SurfaceControl on a helper thread as
46 // SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held.
47 class SurfaceControlHolder {
48 public:
SurfaceControlHolder(sp<SurfaceControl> sc)49     explicit SurfaceControlHolder(sp<SurfaceControl> sc) : mSurfaceControl(std::move(sc)){};
50 
~SurfaceControlHolder()51     ~SurfaceControlHolder() {
52         // Hand the sp<SurfaceControl> to the helper thread to release the last
53         // reference. This makes sure that the SurfaceControl is destructed without
54         // SurfaceFlinger::mStateLock held.
55         BackgroundExecutor::getInstance().sendCallbacks(
56                 {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }});
57     }
58 
createSurfaceControlHolder(const String8 & name)59     static std::unique_ptr<SurfaceControlHolder> createSurfaceControlHolder(const String8& name) {
60         sp<SurfaceControl> surfaceControl =
61                 SurfaceComposerClient::getDefault()
62                         ->createSurface(name, kBufferWidth, kBufferHeight, PIXEL_FORMAT_RGBA_8888,
63                                         ISurfaceComposerClient::eFXSurfaceBufferState);
64         return std::make_unique<SurfaceControlHolder>(std::move(surfaceControl));
65     }
66 
get()67     const sp<SurfaceControl>& get() const { return mSurfaceControl; }
68 
69 private:
70     sp<SurfaceControl> mSurfaceControl;
71 };
72 
73 // Helper class to draw digit and decimal point.
74 class SegmentDrawer {
75 public:
76     enum class Segment {
77         Upper,
78         UpperLeft,
79         UpperRight,
80         Middle,
81         LowerLeft,
82         LowerRight,
83         Bottom,
84         DecimalPoint
85     };
drawSegment(Segment segment,int left,SkColor color,SkCanvas & canvas)86     static void drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) {
87         const SkRect rect = [&]() {
88             switch (segment) {
89                 case Segment::Upper:
90                     return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace);
91                 case Segment::UpperLeft:
92                     return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2.);
93                 case Segment::UpperRight:
94                     return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth,
95                                             kDigitHeight / 2.);
96                 case Segment::Middle:
97                     return SkRect::MakeLTRB(left, kDigitHeight / 2. - kDigitSpace / 2.,
98                                             left + kDigitWidth,
99                                             kDigitHeight / 2. + kDigitSpace / 2.);
100                 case Segment::LowerLeft:
101                     return SkRect::MakeLTRB(left, kDigitHeight / 2., left + kDigitSpace,
102                                             kDigitHeight);
103                 case Segment::LowerRight:
104                     return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2.,
105                                             left + kDigitWidth, kDigitHeight);
106                 case Segment::Bottom:
107                     return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth,
108                                             kDigitHeight);
109                 case Segment::DecimalPoint:
110                     return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitSpace,
111                                             kDigitHeight);
112             }
113         }();
114 
115         SkPaint paint;
116         paint.setColor(color);
117         paint.setBlendMode(SkBlendMode::kSrc);
118         canvas.drawRect(rect, paint);
119     }
120 
drawDigit(int digit,int left,SkColor color,SkCanvas & canvas)121     static void drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) {
122         if (digit < 0 || digit > 9) return;
123 
124         if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 ||
125             digit == 8 || digit == 9)
126             drawSegment(Segment::Upper, left, color, canvas);
127         if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9)
128             drawSegment(Segment::UpperLeft, left, color, canvas);
129         if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 ||
130             digit == 8 || digit == 9)
131             drawSegment(Segment::UpperRight, left, color, canvas);
132         if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 ||
133             digit == 9)
134             drawSegment(Segment::Middle, left, color, canvas);
135         if (digit == 0 || digit == 2 || digit == 6 || digit == 8)
136             drawSegment(Segment::LowerLeft, left, color, canvas);
137         if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 ||
138             digit == 7 || digit == 8 || digit == 9)
139             drawSegment(Segment::LowerRight, left, color, canvas);
140         if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 ||
141             digit == 9)
142             drawSegment(Segment::Bottom, left, color, canvas);
143     }
144 };
145 
146 } // namespace android
147