1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components/chart/rosen_render_chart.h"
17 
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/core/SkColor.h"
20 #include "include/core/SkPaint.h"
21 #include "include/effects/Sk1DPathEffect.h"
22 #include "include/effects/SkGradientShader.h"
23 #endif
24 #ifndef USE_GRAPHIC_TEXT_GINE
25 #include "txt/paragraph_builder.h"
26 #include "txt/paragraph_txt.h"
27 #else
28 #include "rosen_text/typography.h"
29 #include "rosen_text/typography_create.h"
30 #endif
31 
32 #include "core/components/font/rosen_font_collection.h"
33 #include "core/pipeline/base/rosen_render_context.h"
34 
35 namespace OHOS::Ace {
36 namespace {
37 
38 #ifndef WEARABLE_PRODUCT
39 constexpr double EDGE_PADDING = 20.0;
40 constexpr double TEXT_PADDING = 10.0;
41 #else
42 constexpr double EDGE_PADDING = 2.0;
43 constexpr double TEXT_PADDING = 1.0;
44 #endif
45 constexpr double TICK_LENGTH = 5.0;
46 constexpr double RATIO_CONSTANT = 1.732;
47 constexpr double BARS_INTERVAL_PROPORTION = 0.3;
48 constexpr double BAR_INTERVAL_PROPORTION = 0.1;
49 constexpr double DEFAULT_AXISTICK = 10.0;
50 constexpr double DEFAULT_AXIS_STROKE_WIDTH = 3.0;
51 constexpr double BEZIER_CONSTANT = 6.0;
52 constexpr double DOUBLE_TEXT_PADDING = TEXT_PADDING * 2;
53 constexpr int32_t MIN_SDK_VERSION = 6;
54 
55 } // namespace
56 
Update(const RefPtr<Component> & component)57 void RosenRenderChart::Update(const RefPtr<Component>& component)
58 {
59     RenderChart::Update(component);
60 }
61 
ConvertDataToPosition(const Rect & paintRegion,const PointInfo & point)62 Offset RosenRenderChart::ConvertDataToPosition(const Rect& paintRegion, const PointInfo& point)
63 {
64     double xLength = horizontal_.max - horizontal_.min;
65     double yLength = vertical_.max - vertical_.min;
66     if (NearEqual(xLength, 0.0) || NearEqual(yLength, 0.0)) {
67         return Offset(0, 0);
68     }
69     return Offset(paintRegion.GetOffset().GetX() + (point.GetX() - horizontal_.min) * paintRegion.Width() / xLength,
70         paintRegion.GetOffset().GetY() + paintRegion.Height() -
71             (point.GetY() - vertical_.min) * paintRegion.Height() / yLength);
72 }
73 
Paint(RenderContext & context,const Offset & offset)74 void RosenRenderChart::Paint(RenderContext& context, const Offset& offset)
75 {
76     if (LessOrEqual(vertical_.max, vertical_.min)) {
77         vertical_.min = 0.0;
78         vertical_.max = 100.0;
79     }
80     if (LessOrEqual(horizontal_.max, horizontal_.min)) {
81         horizontal_.min = 0.0;
82         horizontal_.max = 100.0;
83     }
84     Rect verticalPaintRegion =
85         Rect(offset.GetX(), offset.GetY(), GetLayoutSize().Width() * 0.1, GetLayoutSize().Height());
86     Rect horizontalPaintRegion =
87         Rect(offset.GetX(), offset.GetY() + GetLayoutSize().Height() - GetLayoutSize().Height() * 0.1,
88             GetLayoutSize().Width(), GetLayoutSize().Height() * 0.1);
89     Rect dataRegion;
90     if (!vertical_.display && !horizontal_.display && type_ == ChartType::LINE) {
91         dataRegion = Rect(offset.GetX() + EDGE_PADDING, offset.GetY() + DOUBLE_TEXT_PADDING,
92             GetLayoutSize().Width() - 2 * EDGE_PADDING, GetLayoutSize().Height() - 2 * DOUBLE_TEXT_PADDING);
93     } else {
94         PaintVerticalAxis(context, offset, verticalPaintRegion);
95         PaintHorizontalAxis(context, horizontalPaintRegion);
96         dataRegion = Rect(offset.GetX() + tickHorizontalOffset_ + EDGE_PADDING, offset.GetY() + EDGE_PADDING,
97             horizontal_.tickNumber * tickHorizontalOffset_, vertical_.tickNumber * tickOffset_);
98     }
99     if (!dataRegion.IsValid()) {
100         LOGW("chart paint data region is not valid height:%{public}lf, width:%{public}lf. do not paint data",
101             dataRegion.Height(), dataRegion.Width());
102         return;
103     }
104     // We Do not clip here(compare with FlutterRenderChart).
105     // Cliping here may cause Axis not display when horizontal_.display = true or vertical_.display = true
106     paintWidth_ = dataRegion.GetSize().Width();
107     PaintDatas(context, dataRegion);
108 }
109 
110 #ifndef USE_ROSEN_DRAWING
PaintStylePoints(SkCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)111 void RosenRenderChart::PaintStylePoints(SkCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
112 {
113     SkPaint paint;
114     paint.setAntiAlias(true);
115 
116     for (const auto& points : chartData.GetData()) {
117         const PointInfo& point = points.GetPointInfo();
118         if (point.GetDisplay()) {
119             PaintPoint(canvas, ConvertDataToPosition(paintRegion, point), paint, point);
120         }
121     }
122     PointInfo headPoint = chartData.GetHeadPoint();
123     if (headPoint.GetDisplay()) {
124         PaintPoint(canvas, ConvertDataToPosition(paintRegion, headPoint), paint, headPoint);
125     }
126     PointInfo topPoint = chartData.GetTopPoint();
127     if (topPoint.GetDisplay()) {
128         PaintPoint(canvas, ConvertDataToPosition(paintRegion, topPoint), paint, topPoint);
129     }
130     PointInfo bottomPoint = chartData.GetBottomPoint();
131     if (bottomPoint.GetDisplay()) {
132         PaintPoint(canvas, ConvertDataToPosition(paintRegion, bottomPoint), paint, bottomPoint);
133     }
134 }
135 #else
PaintStylePoints(RSCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)136 void RosenRenderChart::PaintStylePoints(RSCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
137 {
138     RSPen pen;
139     RSBrush brush;
140     pen.SetAntiAlias(true);
141     brush.SetAntiAlias(true);
142 
143     for (const auto& points : chartData.GetData()) {
144         const PointInfo& point = points.GetPointInfo();
145         if (point.GetDisplay()) {
146             PaintPoint(canvas, ConvertDataToPosition(paintRegion, point), pen, brush, point);
147         }
148     }
149     PointInfo headPoint = chartData.GetHeadPoint();
150     if (headPoint.GetDisplay()) {
151         PaintPoint(canvas, ConvertDataToPosition(paintRegion, headPoint), pen, brush, headPoint);
152     }
153     PointInfo topPoint = chartData.GetTopPoint();
154     if (topPoint.GetDisplay()) {
155         PaintPoint(canvas, ConvertDataToPosition(paintRegion, topPoint), pen, brush, topPoint);
156     }
157     PointInfo bottomPoint = chartData.GetBottomPoint();
158     if (bottomPoint.GetDisplay()) {
159         PaintPoint(canvas, ConvertDataToPosition(paintRegion, bottomPoint), pen, brush, bottomPoint);
160     }
161 }
162 #endif
163 
164 #ifndef USE_ROSEN_DRAWING
PaintText(SkCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)165 void RosenRenderChart::PaintText(SkCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
166 #else
167 void RosenRenderChart::PaintText(RSCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
168 #endif
169 {
170     if (chartData.GetData().empty()) {
171         return;
172     }
173 
174     auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
175     if (!fontCollection) {
176         LOGW("PaintText: fontCollection is null");
177         return;
178     }
179 #ifndef USE_GRAPHIC_TEXT_GINE
180     txt::ParagraphStyle style;
181     txt::TextStyle txtStyle;
182     txtStyle.font_size = chartData.GetTextSize();
183     txtStyle.font_families = chartData.GetFontFamily();
184     txtStyle.font_weight = txt::FontWeight::w400;
185     std::unique_ptr<txt::ParagraphBuilder> builder;
186     double paragraphSize = paintRegion.Width() / chartData.GetData().size();
187     style.max_lines = 1;
188 #else
189     Rosen::TypographyStyle style;
190     Rosen::TextStyle txtStyle;
191     txtStyle.fontSize = chartData.GetTextSize();
192     txtStyle.fontFamilies = chartData.GetFontFamily();
193     txtStyle.fontWeight = Rosen::FontWeight::W400;
194     std::unique_ptr<Rosen::TypographyCreate> builder;
195     double paragraphSize = paintRegion.Width() / chartData.GetData().size();
196     style.maxLines = 1;
197 #endif
198     for (const auto& point : chartData.GetData()) {
199         const TextInfo& text = point.GetTextInfo();
200         const PointInfo& pointInfo = point.GetPointInfo();
201         Offset pointPosition = ConvertDataToPosition(paintRegion, pointInfo);
202         txtStyle.color = text.GetColor().GetValue();
203 #ifndef USE_GRAPHIC_TEXT_GINE
204         builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
205         builder->PushStyle(txtStyle);
206         builder->AddText(StringUtils::Str8ToStr16(text.GetTextValue()));
207         auto paragraph = builder->Build();
208 #else
209         builder = Rosen::TypographyCreate::Create(style, fontCollection);
210         builder->PushStyle(txtStyle);
211         builder->AppendText(StringUtils::Str8ToStr16(text.GetTextValue()));
212         auto paragraph = builder->CreateTypography();
213 #endif
214         paragraph->Layout(paragraphSize);
215         Size textSize = Size(paragraph->GetMinIntrinsicWidth(), paragraph->GetHeight());
216         if (text.GetPlacement() == Placement::TOP) {
217             paragraph->Paint(canvas, pointPosition.GetX() - textSize.Width() / 2,
218                 pointPosition.GetY() - textSize.Height() - TEXT_PADDING);
219         } else if (text.GetPlacement() == Placement::BOTTOM) {
220             paragraph->Paint(canvas, pointPosition.GetX() - textSize.Width() / 2,
221                 pointPosition.GetY() + TEXT_PADDING);
222         }
223     }
224 }
225 
226 #ifndef USE_ROSEN_DRAWING
SetEdgeStyle(const PointInfo & point,SkPaint & paint) const227 void RosenRenderChart::SetEdgeStyle(const PointInfo& point, SkPaint& paint) const
228 {
229     paint.setStyle(SkPaint::Style::kStroke_Style);
230     paint.setStrokeWidth(NormalizeToPx(point.GetPointStrokeWidth()));
231     paint.setColor(point.GetStrokeColor().GetValue());
232 }
233 #else
SetEdgeStyle(const PointInfo & point,RSPen & pen) const234 void RosenRenderChart::SetEdgeStyle(const PointInfo& point, RSPen& pen) const
235 {
236     pen.SetWidth(NormalizeToPx(point.GetPointStrokeWidth()));
237     pen.SetColor(point.GetStrokeColor().GetValue());
238 }
239 #endif
240 
241 #ifndef USE_ROSEN_DRAWING
PaintPoint(SkCanvas * canvas,const Offset & offset,SkPaint paint,const PointInfo & point)242 void RosenRenderChart::PaintPoint(SkCanvas* canvas, const Offset& offset, SkPaint paint, const PointInfo& point)
243 {
244     paint.setColor(point.GetFillColor().GetValue());
245     paint.setStyle(SkPaint::Style::kFill_Style);
246     double pointSize = NormalizeToPx(point.GetPointSize());
247     double halfThickness = NormalizeToPx(point.GetPointStrokeWidth()) / 2;
248     double innerRadius = pointSize / 2 - halfThickness;
249     // first fill point color, then draw edge of point.
250     switch (point.GetPointShape()) {
251         case PointShape::CIRCLE: {
252             canvas->drawCircle(offset.GetX(), offset.GetY(), innerRadius, paint);
253             SetEdgeStyle(point, paint);
254             canvas->drawCircle(offset.GetX(), offset.GetY(), pointSize / 2, paint);
255             break;
256         }
257         case PointShape::SQUARE: {
258             canvas->drawRect(SkRect::MakeLTRB(offset.GetX() - innerRadius, offset.GetY() - innerRadius,
259                                               offset.GetX() + innerRadius, offset.GetY() + innerRadius),
260                 paint);
261             SetEdgeStyle(point, paint);
262             canvas->drawRect(SkRect::MakeLTRB(offset.GetX() - pointSize / 2, offset.GetY() - pointSize / 2,
263                                               offset.GetX() + pointSize / 2, offset.GetY() + pointSize / 2),
264                 paint);
265             break;
266         }
267         case PointShape::TRIANGLE: {
268             SkPath path;
269             path.moveTo(offset.GetX(), offset.GetY() - innerRadius);
270             path.lineTo(offset.GetX() - RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
271             path.lineTo(offset.GetX() + RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
272             path.close();
273             canvas->drawPath(path, paint);
274             path.reset();
275             path.moveTo(offset.GetX(), offset.GetY() - pointSize / 2);
276             path.lineTo(offset.GetX() - RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
277             path.lineTo(offset.GetX() + RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
278             path.close();
279             SetEdgeStyle(point, paint);
280             canvas->drawPath(path, paint);
281             break;
282         }
283         default: {
284             canvas->drawCircle(offset.GetX(), offset.GetY(), innerRadius, paint);
285             SetEdgeStyle(point, paint);
286             canvas->drawCircle(offset.GetX(), offset.GetY(), pointSize / 2, paint);
287             break;
288         }
289     }
290 }
291 #else
PaintPoint(RSCanvas * canvas,const Offset & offset,RSPen pen,RSBrush brush,const PointInfo & point)292 void RosenRenderChart::PaintPoint(
293     RSCanvas* canvas, const Offset& offset, RSPen pen, RSBrush brush, const PointInfo& point)
294 {
295     pen.SetColor(point.GetFillColor().GetValue());
296     brush.SetColor(point.GetFillColor().GetValue());
297 
298     double pointSize = NormalizeToPx(point.GetPointSize());
299     double halfThickness = NormalizeToPx(point.GetPointStrokeWidth()) / 2;
300     double innerRadius = pointSize / 2 - halfThickness;
301     // first fill point color, then draw edge of point.
302     switch (point.GetPointShape()) {
303         case PointShape::CIRCLE: {
304             canvas->AttachBrush(brush);
305             canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), innerRadius);
306             canvas->DetachBrush();
307             SetEdgeStyle(point, pen);
308             canvas->AttachPen(pen);
309             canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), pointSize / 2);
310             canvas->DetachPen();
311             break;
312         }
313         case PointShape::SQUARE: {
314             canvas->AttachBrush(brush);
315             canvas->DrawRect(RSRect(offset.GetX() - innerRadius, offset.GetY() - innerRadius,
316                 offset.GetX() + innerRadius, offset.GetY() + innerRadius));
317             canvas->DetachBrush();
318             SetEdgeStyle(point, pen);
319             canvas->AttachPen(pen);
320             canvas->DrawRect(RSRect(offset.GetX() - pointSize / 2, offset.GetY() - pointSize / 2,
321                 offset.GetX() + pointSize / 2, offset.GetY() + pointSize / 2));
322             canvas->DetachPen();
323             break;
324         }
325         case PointShape::TRIANGLE: {
326             RSRecordingPath path;
327             path.MoveTo(offset.GetX(), offset.GetY() - innerRadius);
328             path.LineTo(offset.GetX() - RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
329             path.LineTo(offset.GetX() + RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
330             path.Close();
331             canvas->AttachBrush(brush);
332             canvas->DrawPath(path);
333             canvas->DetachBrush();
334             path.Reset();
335             path.MoveTo(offset.GetX(), offset.GetY() - pointSize / 2);
336             path.LineTo(offset.GetX() - RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
337             path.LineTo(offset.GetX() + RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
338             path.Close();
339             SetEdgeStyle(point, pen);
340             canvas->AttachPen(pen);
341             canvas->DrawPath(path);
342             canvas->DetachPen();
343             break;
344         }
345         default: {
346             canvas->AttachBrush(brush);
347             canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), innerRadius);
348             canvas->DetachBrush();
349             SetEdgeStyle(point, pen);
350             canvas->AttachPen(pen);
351             canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), pointSize / 2);
352             canvas->DetachPen();
353             break;
354         }
355     }
356 }
357 #endif
358 
PaintDatas(RenderContext & context,const Rect & paintRect)359 void RosenRenderChart::PaintDatas(RenderContext& context, const Rect& paintRect)
360 {
361     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
362     if (!canvas) {
363         LOGE("Paint canvas is null");
364         return;
365     }
366     if (NearEqual(paintRect.Width(), 0.0) || NearEqual(paintRect.Height(), 0.0)) {
367         LOGE("data paint region width:%{public}lf height:%{public}lf", paintRect.Width(), paintRect.Height());
368         return;
369     }
370     if (type_ == ChartType::LINE) {
371         PaintLinearGraph(canvas, paintRect);
372     } else {
373 #ifndef USE_ROSEN_DRAWING
374         SkPaint paint;
375         paint.setAntiAlias(true);
376         paint.setStyle(SkPaint::Style::kStrokeAndFill_Style);
377 #else
378         RSPen pen;
379         RSBrush brush;
380         pen.SetAntiAlias(true);
381         brush.SetAntiAlias(true);
382 #endif
383 
384         const int32_t barGroupNumber = static_cast<int32_t>(mainCharts_.size());
385         auto barsAreaNumber = horizontal_.tickNumber;
386         for (int32_t barGroupIndex = 0; barGroupIndex < barGroupNumber; ++barGroupIndex) {
387             auto barGroup = mainCharts_[barGroupIndex];
388 #ifndef USE_ROSEN_DRAWING
389             paint.setColor(barGroup.GetFillColor().GetValue());
390             PaintBar(canvas, paint, barGroup.GetData(), paintRect, barGroupNumber, barsAreaNumber, barGroupIndex);
391 #else
392             pen.SetColor(barGroup.GetFillColor().GetValue());
393             brush.SetColor(barGroup.GetFillColor().GetValue());
394             PaintBar(canvas, pen, brush, barGroup.GetData(), paintRect, barGroupNumber, barsAreaNumber, barGroupIndex);
395 #endif
396         }
397     }
398 }
399 
UpdateLineGradientPoint(const std::vector<LineInfo> & pointInfo,const MainChart & line,const Rect & paintRect)400 void RosenRenderChart::UpdateLineGradientPoint(
401     const std::vector<LineInfo>& pointInfo, const MainChart& line, const Rect& paintRect)
402 {
403     if (line.GetHeadPointIndex() > 0 && line.GetErasePointNumber() > 0) {
404         startGradientIndex_ = static_cast<size_t>(line.GetHeadPointIndex() + line.GetErasePointNumber() - 1);
405         endGradientIndex_ = startGradientIndex_ + 1;
406         if (static_cast<size_t>(startGradientIndex_) >= pointInfo.size()) {
407             startGradientIndex_ = pointInfo.size() - 1;
408         }
409         if (static_cast<size_t>(endGradientIndex_) >= pointInfo.size()) {
410             endGradientIndex_ = pointInfo.size() - 1;
411         }
412         startGradientPoint_ = ConvertDataToPosition(paintRect, pointInfo[startGradientIndex_].GetPointInfo());
413         endGradientPoint_ = ConvertDataToPosition(paintRect, pointInfo[endGradientIndex_].GetPointInfo());
414     } else {
415         startGradientPoint_ = Offset(0.0, 0.0);
416         endGradientPoint_ = Offset(0.0, 0.0);
417         gradientOfLine_ = false;
418     }
419 }
420 
421 #ifndef USE_ROSEN_DRAWING
PaintLinearGraph(SkCanvas * canvas,const Rect & paintRect)422 void RosenRenderChart::PaintLinearGraph(SkCanvas* canvas, const Rect& paintRect)
423 #else
424 void RosenRenderChart::PaintLinearGraph(RSCanvas* canvas, const Rect& paintRect)
425 #endif
426 {
427     for (const auto& line : mainCharts_) {
428         const auto& pointInfo = line.GetData();
429         if (pointInfo.empty()) {
430             // there is no data in current data set, and skip this line
431             continue;
432         }
433         auto previousSegment = pointInfo[0].GetSegmentInfo();
434         auto previousPoint = pointInfo[0].GetPointInfo();
435         Offset previousPosition = ConvertDataToPosition(paintRect, previousPoint);
436         startOffset_ = previousPosition;
437 #ifndef USE_ROSEN_DRAWING
438         SkPath edgePath;
439         SkPath gradientPath;
440         edgePath.moveTo(previousPosition.GetX(), previousPosition.GetY());
441         gradientPath.moveTo(previousPosition.GetX(), paintRect.Bottom());
442         gradientPath.lineTo(previousPosition.GetX(), previousPosition.GetY());
443 #else
444         RSRecordingPath edgePath;
445         RSRecordingPath gradientPath;
446         edgePath.MoveTo(previousPosition.GetX(), previousPosition.GetY());
447         gradientPath.MoveTo(previousPosition.GetX(), paintRect.Bottom());
448         gradientPath.LineTo(previousPosition.GetX(), previousPosition.GetY());
449 #endif
450 
451         UpdateLineGradientPoint(pointInfo, line, paintRect);
452 
453         for (size_t index = 1; index < pointInfo.size(); index++) {
454             const auto& currentPoint = pointInfo[index].GetPointInfo();
455             Offset currentPosition = ConvertDataToPosition(paintRect, currentPoint);
456             if (line.GetSmoothFlag()) {
457                 bool isEnd = previousSegment != pointInfo[index].GetSegmentInfo();
458                 AddCubicPath(gradientPath, paintRect, line.GetData(), index, isEnd);
459                 AddCubicPath(edgePath, paintRect, line.GetData(), index, isEnd);
460             } else {
461 #ifndef USE_ROSEN_DRAWING
462                 gradientPath.lineTo(currentPosition.GetX(), currentPosition.GetY());
463                 edgePath.lineTo(currentPosition.GetX(), currentPosition.GetY());
464 #else
465                 gradientPath.LineTo(currentPosition.GetX(), currentPosition.GetY());
466                 edgePath.LineTo(currentPosition.GetX(), currentPosition.GetY());
467 #endif
468             }
469             wholeLineGradient_ = line.GetWholeLineGradient();
470             if (wholeLineGradient_) {
471                 targetColor_ = line.GetTargetColor();
472             }
473             int32_t i = static_cast<int32_t>(index);
474             if ((line.GetHeadPointIndex() > 0) && (i > line.GetHeadPointIndex()) &&
475                 (i <= line.GetHeadPointIndex() + line.GetErasePointNumber())) {
476 #ifndef USE_ROSEN_DRAWING
477                 gradientPath.reset();
478                 if (i < line.GetHeadPointIndex() + line.GetErasePointNumber()) {
479                     edgePath.reset();
480                     edgePath.moveTo(currentPosition.GetX(), currentPosition.GetY());
481                 } else {
482                     edgePath.lineTo(currentPosition.GetX(), currentPosition.GetY());
483                     gradientPath.moveTo(currentPosition.GetX(), paintRect.Bottom());
484                     gradientPath.lineTo(currentPosition.GetX(), currentPosition.GetY());
485                     gradientOfLine_ = true;
486                 }
487 #else
488                 gradientPath.Reset();
489                 if (i < line.GetHeadPointIndex() + line.GetErasePointNumber()) {
490                     edgePath.Reset();
491                     edgePath.MoveTo(currentPosition.GetX(), currentPosition.GetY());
492                 } else {
493                     edgePath.LineTo(currentPosition.GetX(), currentPosition.GetY());
494                     gradientPath.MoveTo(currentPosition.GetX(), paintRect.Bottom());
495                     gradientPath.LineTo(currentPosition.GetX(), currentPosition.GetY());
496                     gradientOfLine_ = true;
497                 }
498 #endif
499                 previousSegment = pointInfo[index].GetSegmentInfo();
500                 previousPoint = currentPoint;
501                 previousPosition = currentPosition;
502                 continue;
503             }
504             if (previousSegment != pointInfo[index].GetSegmentInfo() ||
505                 (line.GetHeadPointIndex() > 0 && line.GetHeadPointIndex() == i)) {
506 #ifndef USE_ROSEN_DRAWING
507                 gradientPath.lineTo(currentPosition.GetX(), paintRect.Bottom());
508                 gradientPath.close();
509                 if (line.GetGradient()) {
510                     PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
511                 }
512                 PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), false);
513                 // print gradient
514                 gradientPath.reset();
515                 edgePath.reset();
516                 previousSegment = pointInfo[index].GetSegmentInfo();
517                 previousPoint = currentPoint;
518                 previousPosition = currentPosition;
519                 edgePath.moveTo(previousPosition.GetX(), previousPosition.GetY());
520                 gradientPath.moveTo(previousPosition.GetX(), paintRect.Bottom());
521                 gradientPath.lineTo(previousPosition.GetX(), previousPosition.GetY());
522 #else
523                 gradientPath.LineTo(currentPosition.GetX(), paintRect.Bottom());
524                 gradientPath.Close();
525                 if (line.GetGradient()) {
526                     PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
527                 }
528                 PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), false);
529                 // print gradient
530                 gradientPath.Reset();
531                 edgePath.Reset();
532                 previousSegment = pointInfo[index].GetSegmentInfo();
533                 previousPoint = currentPoint;
534                 previousPosition = currentPosition;
535                 edgePath.MoveTo(previousPosition.GetX(), previousPosition.GetY());
536                 gradientPath.MoveTo(previousPosition.GetX(), paintRect.Bottom());
537                 gradientPath.LineTo(previousPosition.GetX(), previousPosition.GetY());
538 #endif
539             } else {
540                 previousSegment = pointInfo[index].GetSegmentInfo();
541                 previousPoint = currentPoint;
542                 previousPosition = currentPosition;
543             }
544         }
545 #ifndef USE_ROSEN_DRAWING
546         gradientPath.lineTo(previousPosition.GetX(), paintRect.Bottom());
547         gradientPath.close();
548 #else
549         gradientPath.LineTo(previousPosition.GetX(), paintRect.Bottom());
550         gradientPath.Close();
551 #endif
552         if (line.GetGradient()) {
553             PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
554         }
555         PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), true);
556         PaintStylePoints(canvas, paintRect, line);
557         PaintText(canvas, paintRect, line);
558     }
559 }
560 
561 #ifndef USE_ROSEN_DRAWING
PaintLineEdge(SkCanvas * canvas,SkPath & path,const SegmentInfo segmentInfo,double thickness,bool drawGradient)562 void RosenRenderChart::PaintLineEdge(
563     SkCanvas* canvas, SkPath& path, const SegmentInfo segmentInfo, double thickness, bool drawGradient)
564 {
565     SkPaint paint;
566     paint.setAntiAlias(true);
567     paint.setColor(segmentInfo.GetSegmentColor().GetValue());
568     if (segmentInfo.GetLineType() == LineType::DASHED) {
569         SkPath subPath;
570         subPath.addRRect(
571             SkRRect::MakeRectXY(SkRect::MakeXYWH(0.0, -0.5 * thickness, segmentInfo.GetSolidWidth(), thickness),
572                 0.5 * thickness, 0.5 * thickness));
573         paint.setPathEffect(SkPath1DPathEffect::Make(subPath, segmentInfo.GetSpaceWidth() +
574             segmentInfo.GetSolidWidth(), 5.0f, SkPath1DPathEffect::kMorph_Style));
575     } else {
576         paint.setStrokeWidth(thickness);
577     }
578     if (wholeLineGradient_) {
579         double end = startGradientPoint_.GetX();
580         if (NearZero(end)) {
581             end = startOffset_.GetX() + paintWidth_;
582         }
583         SkPoint points[2] = { SkPoint::Make(startOffset_.GetX(), 0.0f), SkPoint::Make(end, 0.0f) };
584         SkColor colors[2] = { segmentInfo.GetSegmentColor().GetValue(), targetColor_.GetValue() };
585         paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr));
586     }
587     if (gradientOfLine_ && drawGradient) {
588         SkPoint points[2] = { SkPoint::Make(startGradientPoint_.GetX(), 0.0f),
589             SkPoint::Make(endGradientPoint_.GetX(), 0.0f) };
590         SkColor colors[2] = { segmentInfo.GetSegmentColor().ChangeAlpha(0).GetValue(),
591             segmentInfo.GetSegmentColor().GetValue() };
592         paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr));
593     }
594     paint.setStyle(SkPaint::Style::kStroke_Style);
595     canvas->drawPath(path, paint);
596 }
597 #else
PaintLineEdge(RSCanvas * canvas,RSPath & path,const SegmentInfo segmentInfo,double thickness,bool drawGradient)598 void RosenRenderChart::PaintLineEdge(
599     RSCanvas* canvas, RSPath& path, const SegmentInfo segmentInfo, double thickness, bool drawGradient)
600 {
601     RSPen pen;
602     pen.SetAntiAlias(true);
603     pen.SetColor(segmentInfo.GetSegmentColor().GetValue());
604     if (segmentInfo.GetLineType() == LineType::DASHED) {
605         RSRecordingPath subPath;
606         subPath.AddRoundRect(
607             RSRoundRect(RSRect(0.0, -0.5 * thickness, segmentInfo.GetSolidWidth(), thickness - 0.5 * thickness),
608                 0.5 * thickness, 0.5 * thickness));
609         pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(
610             subPath, segmentInfo.GetSpaceWidth() + segmentInfo.GetSolidWidth(), 5.0f, RSPathDashStyle::MORPH));
611     } else {
612         pen.SetWidth(thickness);
613     }
614     if (wholeLineGradient_) {
615         double end = startGradientPoint_.GetX();
616         if (NearZero(end)) {
617             end = startOffset_.GetX() + paintWidth_;
618         }
619         std::vector<RSPoint> points = { RSPoint(startOffset_.GetX(), 0.0f), RSPoint(end, 0.0f) };
620         std::vector<RSColorQuad> colors = { segmentInfo.GetSegmentColor().GetValue(), targetColor_.GetValue() };
621         std::vector<RSScalar> pos = { 0.0f };
622         pen.SetShaderEffect(
623             RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP));
624     }
625     if (gradientOfLine_ && drawGradient) {
626         std::vector<RSPoint> points = { RSPoint(startGradientPoint_.GetX(), 0.0f),
627             RSPoint(endGradientPoint_.GetX(), 0.0f) };
628         std::vector<RSColorQuad> colors = { segmentInfo.GetSegmentColor().ChangeAlpha(0).GetValue(),
629             segmentInfo.GetSegmentColor().GetValue() };
630         std::vector<RSScalar> pos = { 0.0f };
631         pen.SetShaderEffect(
632             RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP));
633     }
634     canvas->AttachPen(pen);
635     canvas->DrawPath(path);
636     canvas->DetachPen();
637 }
638 #endif
639 
640 #ifndef USE_ROSEN_DRAWING
PaintLineGradient(SkCanvas * canvas,SkPath & path,const Rect & paintRect,Color fillColor,const PointInfo & peekPoint)641 void RosenRenderChart::PaintLineGradient(
642     SkCanvas* canvas, SkPath& path, const Rect& paintRect, Color fillColor, const PointInfo& peekPoint)
643 {
644     SkPaint paint;
645     paint.setAntiAlias(true);
646     paint.setShader(CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
647 
648     paint.setStyle(SkPaint::Style::kStrokeAndFill_Style);
649     canvas->drawPath(path, paint);
650 }
651 #else
PaintLineGradient(RSCanvas * canvas,RSPath & path,const Rect & paintRect,Color fillColor,const PointInfo & peekPoint)652 void RosenRenderChart::PaintLineGradient(
653     RSCanvas* canvas, RSPath& path, const Rect& paintRect, Color fillColor, const PointInfo& peekPoint)
654 {
655     RSPen pen;
656     RSBrush brush;
657     pen.SetAntiAlias(true);
658     brush.SetAntiAlias(true);
659     pen.SetShaderEffect(
660         CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
661     brush.SetShaderEffect(
662         CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
663     canvas->AttachPen(pen);
664     canvas->AttachBrush(brush);
665     canvas->DrawPath(path);
666     canvas->DetachPen();
667     canvas->DetachBrush();
668 }
669 #endif
670 
671 #ifndef USE_ROSEN_DRAWING
CreateFillGradientShader(const Rect & paintRect,const Color & fillColor,double top)672 sk_sp<SkShader> RosenRenderChart::CreateFillGradientShader(const Rect& paintRect, const Color& fillColor, double top)
673 {
674     SkPoint points[2] = { SkPoint::Make(paintRect.GetOffset().GetX(), top),
675         SkPoint::Make(paintRect.GetOffset().GetX(), paintRect.GetOffset().GetY() + paintRect.Height()) };
676     SkColor colors[2] = { fillColor.GetValue(), fillColor.ChangeAlpha(0).GetValue() };
677     return SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr);
678 }
679 #else
CreateFillGradientShader(const Rect & paintRect,const Color & fillColor,double top)680 std::shared_ptr<RSShaderEffect> RosenRenderChart::CreateFillGradientShader(
681     const Rect& paintRect, const Color& fillColor, double top)
682 {
683     std::vector<RSPoint> points = { RSPoint(paintRect.GetOffset().GetX(), top),
684         RSPoint(paintRect.GetOffset().GetX(), paintRect.GetOffset().GetY() + paintRect.Height()) };
685     std::vector<RSColorQuad> colors = { fillColor.GetValue(), fillColor.ChangeAlpha(0).GetValue() };
686     std::vector<RSScalar> pos = { 0.0f };
687 
688     return RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP);
689 }
690 #endif
691 
CalculateControlA(const Offset & prev,const Offset & cur,const Offset & next)692 Offset RosenRenderChart::CalculateControlA(const Offset& prev, const Offset& cur, const Offset& next)
693 {
694     return Offset(cur.GetX() + (next.GetX() - prev.GetX()) / BEZIER_CONSTANT,
695         cur.GetY() + (next.GetY() - prev.GetY()) / BEZIER_CONSTANT);
696 }
697 
CalculateControlB(const Offset & cur,const Offset & next,const Offset & nextNext)698 Offset RosenRenderChart::CalculateControlB(const Offset& cur, const Offset& next, const Offset& nextNext)
699 {
700     return Offset(next.GetX() - (nextNext.GetX() - cur.GetX()) / BEZIER_CONSTANT,
701         next.GetY() - (nextNext.GetY() - cur.GetY()) / BEZIER_CONSTANT);
702 }
703 
704 #ifndef USE_ROSEN_DRAWING
PaintLine(uint32_t startIndex,const std::vector<LineInfo> & line,SkPath & path,const MainChart & data,const Rect & paintRect)705 int32_t RosenRenderChart::PaintLine(
706     uint32_t startIndex, const std::vector<LineInfo>& line, SkPath& path, const MainChart& data, const Rect& paintRect)
707 #else
708 int32_t RosenRenderChart::PaintLine(
709     uint32_t startIndex, const std::vector<LineInfo>& line, RSPath& path, const MainChart& data, const Rect& paintRect)
710 #endif
711 {
712     uint32_t index = startIndex;
713     startIndex_ = startIndex;
714     bool startPoint = true;
715     for (; index < line.size(); index++) {
716         const auto& point = line[index].GetPointInfo();
717         if (point.GetX() > horizontal_.max || point.GetX() < horizontal_.min || point.GetY() > vertical_.max ||
718             point.GetY() < vertical_.min) {
719             continue;
720         }
721         if (startPoint) {
722             Offset position = ConvertDataToPosition(paintRect, point);
723 #ifndef USE_ROSEN_DRAWING
724             if (data.GetGradient() && !drawLine_) {
725                 path.moveTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
726                 path.lineTo(position.GetX(), position.GetY());
727             } else {
728                 path.moveTo(position.GetX(), position.GetY());
729             }
730 #else
731             if (data.GetGradient() && !drawLine_) {
732                 path.MoveTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
733                 path.LineTo(position.GetX(), position.GetY());
734             } else {
735                 path.MoveTo(position.GetX(), position.GetY());
736             }
737 #endif
738             startPoint = false;
739         } else if (index == line.size() - 1 ||
740                    (data.GetHeadPointIndex() >= 0 && (index == static_cast<uint32_t>(data.GetHeadPointIndex())))) {
741             Offset position = ConvertDataToPosition(paintRect, point);
742 #ifndef USE_ROSEN_DRAWING
743             if (data.GetSmoothFlag()) {
744                 AddCubicPath(path, paintRect, line, index, true);
745             } else {
746                 path.lineTo(position.GetX(), position.GetY());
747             }
748             if (data.GetGradient() && !drawLine_) {
749                 path.lineTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
750             }
751 #else
752             if (data.GetSmoothFlag()) {
753                 AddCubicPath(path, paintRect, line, index, true);
754             } else {
755                 path.LineTo(position.GetX(), position.GetY());
756             }
757             if (data.GetGradient() && !drawLine_) {
758                 path.LineTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
759             }
760 #endif
761             index += 1;
762             break;
763         } else {
764             if (data.GetSmoothFlag()) {
765                 AddCubicPath(path, paintRect, line, index, false);
766             } else {
767                 Offset position = ConvertDataToPosition(paintRect, point);
768 #ifndef USE_ROSEN_DRAWING
769                 path.lineTo(position.GetX(), position.GetY());
770 #else
771                 path.LineTo(position.GetX(), position.GetY());
772 #endif
773             }
774         }
775     }
776     return index;
777 }
778 
779 #ifndef USE_ROSEN_DRAWING
AddCubicPath(SkPath & path,const Rect & paintRect,const std::vector<LineInfo> & line,uint32_t index,bool isEnd)780 void RosenRenderChart::AddCubicPath(
781     SkPath& path, const Rect& paintRect, const std::vector<LineInfo>& line, uint32_t index, bool isEnd)
782 #else
783 void RosenRenderChart::AddCubicPath(
784     RSPath& path, const Rect& paintRect, const std::vector<LineInfo>& line, uint32_t index, bool isEnd)
785 #endif
786 {
787     // use control point A = [(Xi + (Xi+1 - Xi-1) / 4), (Yi + (Yi+1 - Yi-1) / 4)]
788     // and control point B = [(Xi+1 - (Xi+2 - Xi) / 4), (Yi+1 - (Yi+2 - Yi) / 4)]
789     if (index > 0 && index < line.size()) {
790         Offset prev = ConvertDataToPosition(
791             paintRect, line[(index < 2 || index - 2 < startIndex_) ? startIndex_ : index - 2].GetPointInfo());
792         Offset cur = ConvertDataToPosition(paintRect, line[index - 1].GetPointInfo());
793         Offset next = ConvertDataToPosition(paintRect, line[index].GetPointInfo());
794         Offset nextNext = ConvertDataToPosition(paintRect,
795             (isEnd || index + 1 >= line.size()) ? line[index].GetPointInfo() : line[index + 1].GetPointInfo());
796         Offset controlA = CalculateControlA(prev, cur, next);
797         Offset controlB = CalculateControlB(cur, next, nextNext);
798 #ifndef USE_ROSEN_DRAWING
799         path.cubicTo(controlA.GetX(), controlA.GetY(), controlB.GetX(), controlB.GetY(), next.GetX(), next.GetY());
800 #else
801         path.CubicTo(controlA.GetX(), controlA.GetY(), controlB.GetX(), controlB.GetY(), next.GetX(), next.GetY());
802 #endif
803     } else {
804         LOGW("index out of region");
805     }
806 }
807 
PaintHorizontalAxis(RenderContext & context,const Rect & paintRect)808 void RosenRenderChart::PaintHorizontalAxis(RenderContext& context, const Rect& paintRect)
809 {
810     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
811     if (!canvas) {
812         LOGE("Paint canvas is null");
813         return;
814     }
815     const Offset offset = paintRect.GetOffset();
816 #ifndef USE_ROSEN_DRAWING
817     SkPaint paint;
818     paint.setAntiAlias(true);
819     paint.setColor(horizontal_.color.GetValue());
820     paint.setStyle(SkPaint::Style::kStroke_Style);
821     paint.setStrokeWidth(DEFAULT_AXIS_STROKE_WIDTH);
822 #else
823     RSPen pen;
824     pen.SetAntiAlias(true);
825     pen.SetColor(horizontal_.color.GetValue());
826     pen.SetWidth(DEFAULT_AXIS_STROKE_WIDTH);
827 #endif
828 
829     if ((horizontal_.tickNumber <= 0) || (horizontal_.tickNumber + 1 == 0)) {
830         horizontal_.tickNumber = DEFAULT_AXISTICK;
831     }
832     tickHorizontalOffset_ = (paintRect.Width() - 2 * EDGE_PADDING) / (horizontal_.tickNumber + 1);
833 
834     if (!horizontal_.display) {
835         return;
836     }
837 
838     double tickPosition = EDGE_PADDING + tickHorizontalOffset_;
839 #ifndef USE_ROSEN_DRAWING
840     for (int32_t index = 0; index < horizontal_.tickNumber; index++) {
841         canvas->drawLine(offset.GetX() + tickPosition, offset.GetY(), offset.GetX() + tickPosition,
842             offset.GetY() + TICK_LENGTH, paint);
843         tickPosition += tickHorizontalOffset_;
844     }
845 
846     canvas->drawLine(offset.GetX(), offset.GetY() + 0.5 * TICK_LENGTH, offset.GetX() + paintRect.Width(),
847         offset.GetY() + 0.5 * TICK_LENGTH, paint);
848 #else
849     canvas->AttachPen(pen);
850     for (int32_t index = 0; index < horizontal_.tickNumber; index++) {
851         canvas->DrawLine(RSPoint(offset.GetX() + tickPosition, offset.GetY()),
852             RSPoint(offset.GetX() + tickPosition, offset.GetY() + TICK_LENGTH));
853         tickPosition += tickHorizontalOffset_;
854     }
855 
856     canvas->DrawLine(RSPoint(offset.GetX(), offset.GetY() + 0.5 * TICK_LENGTH),
857         RSPoint(offset.GetX() + paintRect.Width(), offset.GetY() + 0.5 * TICK_LENGTH));
858     canvas->DetachPen();
859 #endif
860 }
861 
PaintVerticalAxis(RenderContext & context,const Offset & offset,const Rect & paintRect)862 void RosenRenderChart::PaintVerticalAxis(RenderContext& context, const Offset& offset, const Rect& paintRect)
863 {
864     auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
865     if (!canvas) {
866         LOGE("Paint canvas is null");
867         return;
868     }
869 
870 #ifndef USE_ROSEN_DRAWING
871     SkPaint paint;
872     paint.setAntiAlias(true);
873     paint.setColor(vertical_.color.GetValue());
874     paint.setStyle(SkPaint::Style::kStroke_Style);
875     paint.setStrokeWidth(DEFAULT_AXIS_STROKE_WIDTH);
876 #else
877     RSPen pen;
878     pen.SetAntiAlias(true);
879     pen.SetColor(vertical_.color.GetValue());
880     pen.SetWidth(DEFAULT_AXIS_STROKE_WIDTH);
881 #endif
882 
883     if ((vertical_.tickNumber <= 0) || (vertical_.tickNumber + 1 == 0)) {
884         vertical_.tickNumber = DEFAULT_AXISTICK;
885     }
886     tickOffset_ = (paintRect.Height() - 2 * EDGE_PADDING) / (vertical_.tickNumber + 1);
887 
888     if (!vertical_.display) {
889         return;
890     }
891 
892     double tickPosition = EDGE_PADDING + tickOffset_;
893 #ifndef USE_ROSEN_DRAWING
894     for (int32_t index = 0; index < vertical_.tickNumber; index++) {
895         canvas->drawLine(offset.GetX() + paintRect.Width() - TICK_LENGTH, offset.GetY() + tickPosition,
896             offset.GetX() + paintRect.Width(), offset.GetY() + tickPosition, paint);
897         tickPosition += tickOffset_;
898     }
899 
900     canvas->drawLine(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY(),
901         offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY() + paintRect.Height(), paint);
902 #else
903     canvas->AttachPen(pen);
904     for (int32_t index = 0; index < vertical_.tickNumber; index++) {
905         canvas->DrawLine(RSPoint(offset.GetX() + paintRect.Width() - TICK_LENGTH, offset.GetY() + tickPosition),
906             RSPoint(offset.GetX() + paintRect.Width(), offset.GetY() + tickPosition));
907         tickPosition += tickOffset_;
908     }
909 
910     canvas->DrawLine(RSPoint(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY()),
911         RSPoint(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY() + paintRect.Height()));
912     canvas->DetachPen();
913 #endif
914 }
915 
916 #ifndef USE_ROSEN_DRAWING
PaintBar(SkCanvas * canvas,SkPaint & paint,const std::vector<LineInfo> & barGroupData,const Rect & paintRect,int32_t barGroupNum,int32_t barsAreaNum,int32_t barGroupIndex)917 void RosenRenderChart::PaintBar(SkCanvas* canvas, SkPaint& paint, const std::vector<LineInfo>& barGroupData,
918     const Rect& paintRect, int32_t barGroupNum, int32_t barsAreaNum, int32_t barGroupIndex)
919 #else
920 void RosenRenderChart::PaintBar(RSCanvas* canvas, RSPen& pen, RSBrush brush, const std::vector<LineInfo>& barGroupData,
921     const Rect& paintRect, int32_t barGroupNum, int32_t barsAreaNum, int32_t barGroupIndex)
922 #endif
923 {
924     if (NearEqual(paintRect.Width(), 0.0) || NearEqual(paintRect.Height(), 0.0)) {
925         LOGE("data paint region width:%{public}lf height:%{public}lf", paintRect.Width(), paintRect.Height());
926         return;
927     }
928     const int32_t barSize = static_cast<int32_t>(barGroupData.size());
929     for (int32_t barIndex = 0; barIndex < barSize; ++barIndex) {
930         const auto point = barGroupData[barIndex].GetPointInfo();
931         // If the actual number of data exceeds Tick, the extra part will not be laid out
932         if (barIndex >= barsAreaNum) {
933             return;
934         }
935         auto barsAreaPaintRect = GetBarsAreaPaintRect(paintRect, barIndex);
936         double barInterval = BARS_INTERVAL_PROPORTION;
937         auto context = GetContext().Upgrade();
938         if (context && context->GetMinPlatformVersion() >= MIN_SDK_VERSION) {
939             barInterval = 0;
940         }
941         auto barAreaPaintRect = GetBarAreaPaintRect(barsAreaPaintRect, barGroupIndex, barGroupNum, barInterval);
942         Offset position = ConvertDataToPosition(paintRect, point);
943         // barAreaPaintRect left add bar interval is originX
944         auto originX = barAreaPaintRect.GetOffset().GetX() +
945             (BAR_INTERVAL_PROPORTION / 2) * barAreaPaintRect.Width();
946         auto originY = position.GetY();
947 
948 #ifndef USE_ROSEN_DRAWING
949         canvas->drawRect(
950             SkRect::MakeLTRB(originX, originY, originX + barAreaPaintRect.Width() * (1 - BAR_INTERVAL_PROPORTION),
951                 paintRect.GetOffset().GetY() + paintRect.Height()),
952             paint);
953 #else
954         canvas->AttachPen(pen);
955         canvas->AttachBrush(brush);
956         canvas->DrawRect(RSRect(originX, originY, originX + barAreaPaintRect.Width() * (1 - BAR_INTERVAL_PROPORTION),
957             paintRect.GetOffset().GetY() + paintRect.Height()));
958         canvas->DetachPen();
959         canvas->DetachBrush();
960 #endif
961     }
962 }
963 
GetBarsAreaPaintRect(const Rect & paintRect,int32_t barsAreaIndex)964 Rect RosenRenderChart::GetBarsAreaPaintRect(const Rect& paintRect, int32_t barsAreaIndex)
965 {
966     auto barsAreaWidth = paintRect.Width() / horizontal_.tickNumber;
967     auto barsAreaHeight = paintRect.Height();
968     Rect barsAreaRect =
969         Rect(paintRect.Left() + barsAreaIndex * barsAreaWidth, paintRect.Top(), barsAreaWidth, barsAreaHeight);
970     return barsAreaRect;
971 }
972 
GetBarAreaPaintRect(const Rect & barsAreaPaintRect,int32_t barGroupIndex,int32_t barGroupNumber,double barInterval)973 Rect RosenRenderChart::GetBarAreaPaintRect(
974     const Rect& barsAreaPaintRect, int32_t barGroupIndex, int32_t barGroupNumber, double barInterval)
975 {
976     // Divide 30% of the horizontal space of barsArea into 2 parts as left and right intervals,
977     // and divide the remaining part by barGroupNumber to get barAreaWidth
978     auto barAreaWidth = (1 - barInterval) * barsAreaPaintRect.Width() / barGroupNumber;
979     auto barAreaHeight = barsAreaPaintRect.Height();
980     // After leaving the interval, the left border of the barArea area is obtained
981     auto barAreaLeft =
982         barsAreaPaintRect.Left() + barInterval / 2 * barsAreaPaintRect.Width() + barGroupIndex * barAreaWidth;
983     Rect barAreaRect = Rect(barAreaLeft, barsAreaPaintRect.Top(), barAreaWidth, barAreaHeight);
984     return barAreaRect;
985 }
986 
987 } // namespace OHOS::Ace
988