1 /*
2  * Copyright (c) 2022-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_ng/pattern/calendar/calendar_paint_method.h"
17 
18 #include <cstdint>
19 
20 #include "base/geometry/ng/rect_t.h"
21 #include "base/geometry/offset.h"
22 #include "base/geometry/point.h"
23 #include "base/i18n/localization.h"
24 #include "base/memory/referenced.h"
25 #include "base/utils/string_utils.h"
26 #include "base/utils/utils.h"
27 #include "bridge/common/utils/utils.h"
28 #include "core/common/font_manager.h"
29 #include "core/components/calendar/calendar_theme.h"
30 #include "core/components/common/properties/color.h"
31 #include "core/components_ng/pattern/calendar/calendar_pattern.h"
32 #include "core/components_ng/pattern/calendar/calendar_paint_property.h"
33 #include "core/components_ng/render/canvas_image.h"
34 #include "core/components_ng/render/drawing.h"
35 #include "core/components_ng/render/drawing_prop_convertor.h"
36 #include "core/components_ng/render/paint_property.h"
37 
38 namespace OHOS::Ace::NG {
39 
40 namespace {
41 
42 const char ELLIPSIS[] = "...";
43 constexpr int32_t ROW_COUNT_FOUR = 4;
44 constexpr int32_t ROW_COUNT_FIVE = 5;
45 constexpr int32_t ROW_COUNT_SIX = 6;
46 constexpr int32_t TEXT_MAX_LENGTH = 3;
47 constexpr int32_t TEXT_END_INDEX = 2;
48 constexpr int32_t WEEK_TEXT_END_INDEX = 3;
49 constexpr double WEEKEND_TRANSPARENT = 0x7D;
50 constexpr Dimension CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT = 4.0_vp;
51 constexpr double DEVICE_HEIGHT_LIMIT = 640.0;
52 
GetTextParagraph(const std::string & text,const RSTextStyle & textStyle)53 std::unique_ptr<RSParagraph> GetTextParagraph(const std::string& text, const RSTextStyle& textStyle)
54 {
55     RSParagraphStyle style;
56 #ifndef USE_GRAPHIC_TEXT_GINE
57     auto fontCollection = RSFontCollection::GetInstance(false);
58 #else
59     auto fontCollection = RSFontCollection::Create();
60 #endif
61     CHECK_NULL_RETURN(fontCollection, nullptr);
62 #ifndef USE_GRAPHIC_TEXT_GINE
63     std::unique_ptr<RSParagraphBuilder> builder = RSParagraphBuilder::CreateRosenBuilder(style, fontCollection);
64 #else
65     std::unique_ptr<RSParagraphBuilder> builder = RSParagraphBuilder::Create(style, fontCollection);
66 #endif
67     builder->PushStyle(textStyle);
68 #ifndef USE_GRAPHIC_TEXT_GINE
69     builder->AddText(StringUtils::Str8ToStr16(text));
70     return builder->Build();
71 #else
72     builder->AppendText(StringUtils::Str8ToStr16(text));
73     return builder->CreateTypography();
74 #endif
75 }
76 
DrawCalendarText(RSCanvas * canvas,const std::string & text,const RSTextStyle & textStyle,const Rect & boxRect,Rect & textRect)77 void DrawCalendarText(
78     RSCanvas* canvas, const std::string& text, const RSTextStyle& textStyle, const Rect& boxRect, Rect& textRect)
79 {
80     // The lunar calendar description is truncated by more than three characters.
81     std::string newText { text };
82     auto wText = StringUtils::ToWstring(text);
83     if (wText.size() > TEXT_MAX_LENGTH) {
84         wText = wText.substr(0, TEXT_END_INDEX);
85         newText = StringUtils::ToString(wText);
86         newText += ELLIPSIS;
87     }
88 
89     auto paragraph = GetTextParagraph(newText, textStyle);
90     CHECK_NULL_VOID(paragraph);
91     const auto& offset = boxRect.GetOffset();
92     paragraph->Layout(boxRect.Width());
93     double textWidth = paragraph->GetMaxIntrinsicWidth();
94     double textHeight = paragraph->GetHeight();
95     // paint text in center of item
96     double textPaintOffsetX = (boxRect.Width() - textWidth) / 2.0;
97     double textPaintOffsetY = (boxRect.Height() - textHeight) / 2.0;
98     paragraph->Paint(canvas, offset.GetX() + textPaintOffsetX, offset.GetY() + textPaintOffsetY);
99     textRect.SetRect(offset.GetX() + textPaintOffsetX, offset.GetY() + textPaintOffsetY, textWidth, textHeight);
100 }
101 
DrawCalendarText(RSCanvas * canvas,const std::string & text,const RSTextStyle & textStyle,const Rect & boxRect)102 void DrawCalendarText(RSCanvas* canvas, const std::string& text, const RSTextStyle& textStyle, const Rect& boxRect)
103 {
104     Rect textRect;
105     DrawCalendarText(canvas, text, textStyle, boxRect, textRect);
106 }
107 
108 } // namespace
109 
GetContentDrawFunction(PaintWrapper * paintWrapper)110 CanvasDrawFunction CalendarPaintMethod::GetContentDrawFunction(PaintWrapper* paintWrapper)
111 {
112     auto renderContext = paintWrapper->GetRenderContext();
113     CHECK_NULL_RETURN(renderContext, nullptr);
114     auto calendarNode = renderContext->GetHost();
115     CHECK_NULL_RETURN(calendarNode, nullptr);
116     textDirection_ = calendarNode->GetLayoutProperty()->GetNonAutoLayoutDirection();
117 
118     auto paintProperty = DynamicCast<CalendarPaintProperty>(paintWrapper->GetPaintProperty());
119     CHECK_NULL_RETURN(paintProperty, nullptr);
120     frameSize_ = paintWrapper->GetGeometryNode()->GetFrameSize();
121     auto paintFunc = [weak = WeakClaim(this), paintProperty](RSCanvas& canvas) {
122         auto calendar_ = weak.Upgrade();
123         if (calendar_) {
124             calendar_->PaintContent(canvas, paintProperty);
125         }
126     };
127     return paintFunc;
128 }
129 
PaintContent(RSCanvas & canvas,const RefPtr<CalendarPaintProperty> & paintProperty)130 void CalendarPaintMethod::PaintContent(RSCanvas& canvas, const RefPtr<CalendarPaintProperty>& paintProperty)
131 {
132     SetCalendarTheme(paintProperty);
133     DrawWeekAndDates(canvas, offset_);
134 }
135 
DrawWeekAndDates(RSCanvas & canvas,Offset offset)136 void CalendarPaintMethod::DrawWeekAndDates(RSCanvas& canvas, Offset offset)
137 {
138     weekNumbers_ = Localization::GetInstance()->GetWeekdays(true);
139     if (!obtainedMonth_.days.empty()) {
140         calendarDays_.assign(obtainedMonth_.days.begin(), obtainedMonth_.days.end());
141     }
142     offset += (isCalendarDialog_ ? Offset(CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT.ConvertToPx(), 0)
143                                  : Offset(touchCircleStrokeWidth_, 0));
144     DrawWeek(canvas, offset);
145     if (calendarDays_.empty()) {
146         return;
147     }
148     DrawDates(canvas, offset);
149 }
150 
DrawDates(RSCanvas & canvas,const Offset & offset)151 void CalendarPaintMethod::DrawDates(RSCanvas& canvas, const Offset& offset)
152 {
153     uint32_t totalWeek = weekNumbers_.size();
154     int32_t dateNumber = 0;
155     double dailyRowSpace = 0.0;
156     double dayNumberStartY = topPadding_ + weekHeight_ + weekAndDayRowSpace_;
157 
158     // Set the rowCount.
159     if (totalWeek != 0) {
160         rowCount_ = static_cast<int32_t>(calendarDays_.size() / totalWeek);
161     }
162 
163     // Set dailyFourRowSpace_ for four line calendar.
164     // Set dailyFiveRowSpace_ for five line calendar.
165     // Set dailySixRowSpace_ for six line calendar.
166     switch (rowCount_) {
167         case ROW_COUNT_FOUR: {
168             dailyRowSpace = dailyFourRowSpace_;
169             break;
170         }
171         case ROW_COUNT_SIX: {
172             dailyRowSpace = dailySixRowSpace_;
173             break;
174         }
175         case ROW_COUNT_FIVE:
176         default:
177             dailyRowSpace = dailyFiveRowSpace_;
178             break;
179     }
180 
181     for (int32_t row = 0; row < rowCount_; row++) {
182         double y = row * (dayHeight_ + dailyRowSpace) + dayNumberStartY;
183         for (uint32_t column = 0; column < totalWeek; column++) {
184             const auto& day = calendarDays_[dateNumber++];
185             double x = textDirection_ == TextDirection::LTR ? column * (dayWidth_ + colSpace_)
186                                                             : (totalWeek - column - 1) * (dayWidth_ + colSpace_);
187             auto dayOffset = Offset(x, y);
188             DrawCalendar(canvas, offset, dayOffset, day);
189         }
190     }
191 }
192 
DrawCalendar(RSCanvas & canvas,const Offset & offset,const Offset & dayOffset,const CalendarDay & day)193 void CalendarPaintMethod::DrawCalendar(
194     RSCanvas& canvas, const Offset& offset, const Offset& dayOffset, const CalendarDay& day)
195 {
196     RSTextStyle dateTextStyle;
197     RSTextStyle lunarTextStyle;
198     InitTextStyle(dateTextStyle, lunarTextStyle);
199 #ifndef USE_GRAPHIC_TEXT_GINE
200     dateTextStyle.locale_ = Localization::GetInstance()->GetFontLocale();
201     lunarTextStyle.locale_ = Localization::GetInstance()->GetFontLocale();
202 #else
203     dateTextStyle.locale = Localization::GetInstance()->GetFontLocale();
204     lunarTextStyle.locale = Localization::GetInstance()->GetFontLocale();
205 #endif
206 
207     auto x = dayOffset.GetX();
208     auto y = dayOffset.GetY();
209 
210     if (isCalendarDialog_) {
211         x += CALENDAR_DISTANCE_ADJUST_FOCUSED_EVENT.ConvertToPx();
212         SetCalendarPickerDayTextStyle(dateTextStyle, day);
213         DrawCalendarPickerBackgroundArea(day, canvas, x, y);
214 
215         Offset dateNumberOffset = Offset(x, y + (dayHeight_ / 2 - gregorianDayHeight_ / 2));
216         PaintDay(canvas, dateNumberOffset, day, dateTextStyle);
217         return;
218     }
219 
220     // First of all, check whether the day is current month or not, and set text style.
221     SetDayTextStyle(dateTextStyle, lunarTextStyle, day);
222 
223     if (day.focused && day.month.month == currentMonth_.month) {
224         if (IsToday(day)) {
225             DrawTodayArea(canvas, offset, x, y);
226         } else {
227             DrawFocusedArea(canvas, offset, x, y);
228         }
229     }
230 
231     if (showLunar_ && !day.lunarDay.empty()) {
232         // paint day
233         Offset dateNumberOffset = offset + Offset(x, y + gregorianDayYAxisOffset_);
234         PaintDay(canvas, dateNumberOffset, day, dateTextStyle);
235 
236         // paint lunar day
237         Offset lunarDayOffset = offset + Offset(x, y + lunarDayYAxisOffset_);
238         PaintLunarDay(canvas, lunarDayOffset, day, lunarTextStyle);
239     } else {
240         // when there is no lunar calendar, the date is displayed in the center
241         Offset dateNumberOffset = offset + Offset(x, y + (focusedAreaRadius_ - gregorianDayHeight_ / 2));
242         PaintDay(canvas, dateNumberOffset, day, dateTextStyle);
243     }
244 }
245 
DrawTodayArea(RSCanvas & canvas,const Offset & offset,double x,double y) const246 void CalendarPaintMethod::DrawTodayArea(RSCanvas& canvas, const Offset& offset, double x, double y) const
247 {
248     // draw Today background circle
249     RSBrush brush;
250     brush.SetAntiAlias(true);
251     brush.SetColor(focusedAreaBackgroundColor_);
252     canvas.AttachBrush(brush);
253 
254     Offset circleCenter = Offset(x - (focusedAreaRadius_ * 2 - dayWidth_) / 2 + focusedAreaRadius_,
255         y - (1.0_vp).ConvertToPx() + focusedAreaRadius_);
256     Offset bgCircleStart = offset + circleCenter;
257     canvas.DrawCircle(RSPoint(static_cast<float>(bgCircleStart.GetX()), static_cast<float>(bgCircleStart.GetY())),
258         static_cast<float>(focusedAreaRadius_));
259     canvas.DetachBrush();
260 }
261 
DrawFocusedArea(RSCanvas & canvas,const Offset & offset,double x,double y) const262 void CalendarPaintMethod::DrawFocusedArea(RSCanvas& canvas, const Offset& offset, double x, double y) const
263 {
264     // draw focus background circle
265     RSPen pen;
266     pen.SetAntiAlias(true);
267     pen.SetColor(focusedAreaBackgroundColor_);
268     canvas.AttachPen(pen);
269 
270     Offset circleCenter = Offset(x - (focusedAreaRadius_ * 2 - dayWidth_) / 2 + focusedAreaRadius_,
271         y - (1.0_vp).ConvertToPx() + focusedAreaRadius_);
272     Offset bgCircleStart = offset + circleCenter;
273     canvas.DrawCircle(RSPoint(static_cast<float>(bgCircleStart.GetX()), static_cast<float>(bgCircleStart.GetY())),
274         static_cast<float>(focusedAreaRadius_));
275     canvas.DetachPen();
276 }
277 
DrawCalendarPickerBackgroundArea(const CalendarDay & day,RSCanvas & canvas,double x,double y) const278 void CalendarPaintMethod::DrawCalendarPickerBackgroundArea(
279     const CalendarDay& day, RSCanvas& canvas, double x, double y) const
280 {
281     RSBrush brush;
282     brush.SetAntiAlias(true);
283     brush.SetColor(ToRSColor(Color::TRANSPARENT));
284     if (day.month.year == obtainedMonth_.year && day.month.month == obtainedMonth_.month) {
285         if (day.isSelected) {
286             brush.SetColor(IsToday(day) ? backgroundSelectedTodayColor_ : backgroundSelectedNotTodayColor_);
287         } else if (day.isPressing) {
288             brush.SetColor(backgroundPressColor_);
289         } else if (day.isHovering) {
290             brush.SetColor(backgroundHoverColor_);
291         }
292     }
293 
294     canvas.AttachBrush(brush);
295     RSRect rect(static_cast<float>(x), static_cast<float>(y), static_cast<float>(x + dayWidth_),
296         static_cast<float>(y + dayHeight_));
297     auto rrect = RSRoundRect(rect, dayRadius_, dayRadius_);
298     canvas.DrawRoundRect(rrect);
299     canvas.DetachBrush();
300 
301     if (day.isKeyFocused) {
302         RSPen pen;
303         pen.SetAntiAlias(true);
304         pen.SetColor(backgroundKeyFocusedColor_);
305         pen.SetWidth(calendarDayKeyFocusedPenWidth_);
306         canvas.AttachPen(pen);
307 
308         auto focusedX = x - (calendarDayKeyFocusedWidth_ - dayWidth_) / 2 - calendarDayKeyFocusedPenWidth_ / 2;
309         auto focusedY = y - (calendarDayKeyFocusedWidth_ - dayWidth_) / 2 - calendarDayKeyFocusedPenWidth_ / 2;
310         RSRect keyFocusedrect(static_cast<float>(focusedX), static_cast<float>(focusedY),
311             static_cast<float>(focusedX + calendarDayKeyFocusedWidth_ + calendarDayKeyFocusedPenWidth_),
312             static_cast<float>(focusedY + calendarDayKeyFocusedWidth_ + calendarDayKeyFocusedPenWidth_));
313         auto keyFocusedrrect = RSRoundRect(keyFocusedrect,
314             dayRadius_ / dayWidth_ * (calendarDayKeyFocusedWidth_ + calendarDayKeyFocusedPenWidth_),
315             dayRadius_ / dayWidth_ * (calendarDayKeyFocusedWidth_ + calendarDayKeyFocusedPenWidth_));
316         canvas.DrawRoundRect(keyFocusedrrect);
317         canvas.DetachPen();
318     }
319 }
320 
InitTextStyle(RSTextStyle & dateTextStyle,RSTextStyle & lunarTextStyle)321 void CalendarPaintMethod::InitTextStyle(RSTextStyle& dateTextStyle, RSTextStyle& lunarTextStyle)
322 {
323 #ifndef USE_GRAPHIC_TEXT_GINE
324     dateTextStyle.fontSize_ = dayFontSize_;
325     dateTextStyle.fontWeight_ = static_cast<RSFontWeight>(dayFontWeight_);
326 
327     lunarTextStyle.fontSize_ = lunarDayFontSize_;
328     lunarTextStyle.fontWeight_ = static_cast<RSFontWeight>(lunarDayFontWeight_);
329 
330     if (!appFontFamilies_.empty()) {
331         dateTextStyle.fontFamilies_ = appFontFamilies_;
332         lunarTextStyle.fontFamilies_ = appFontFamilies_;
333     }
334 #else
335     dateTextStyle.fontSize = dayFontSize_;
336     dateTextStyle.fontWeight = static_cast<RSFontWeight>(dayFontWeight_);
337 
338     lunarTextStyle.fontSize = lunarDayFontSize_;
339     lunarTextStyle.fontWeight = static_cast<RSFontWeight>(lunarDayFontWeight_);
340 
341     if (!appFontFamilies_.empty()) {
342         dateTextStyle.fontFamilies = appFontFamilies_;
343         lunarTextStyle.fontFamilies = appFontFamilies_;
344     }
345 #endif
346 }
347 
SetDayTextStyle(RSTextStyle & dateTextStyle,RSTextStyle & lunarTextStyle,const CalendarDay & day)348 void CalendarPaintMethod::SetDayTextStyle(
349     RSTextStyle& dateTextStyle, RSTextStyle& lunarTextStyle, const CalendarDay& day)
350 {
351     // Set the noncurrent month style and current month style.
352     if (day.month.month != currentMonth_.month) {
353 #ifndef USE_GRAPHIC_TEXT_GINE
354         dateTextStyle.color_ = nonCurrentMonthDayColor_;
355         lunarTextStyle.color_ = day.markLunarDay ? RSColor(markLunarColor_.GetRed(), markLunarColor_.GetGreen(),
356             markLunarColor_.GetBlue(), WEEKEND_TRANSPARENT) : nonCurrentMonthLunarColor_;
357 #else
358         dateTextStyle.color = nonCurrentMonthDayColor_;
359         lunarTextStyle.color = day.markLunarDay ? RSColor(markLunarColor_.GetRed(), markLunarColor_.GetGreen(),
360             markLunarColor_.GetBlue(), WEEKEND_TRANSPARENT) : nonCurrentMonthLunarColor_;
361 #endif
362     } else {
363 #ifndef USE_GRAPHIC_TEXT_GINE
364         dateTextStyle.color_ = (IsToday(day) && day.focused) ? focusedDayColor_
365                                : IsToday(day)                ? todayDayColor_
366                                : IsOffDay(day)               ? weekendDayColor_
367                                                              : dayColor_;
368         lunarTextStyle.color_ =
369             (IsToday(day) && day.focused) ? focusedLunarColor_
370             : IsToday(day)                ? todayLunarColor_
371                            : (day.markLunarDay ? markLunarColor_ : (IsOffDay(day) ? weekendLunarColor_ : lunarColor_));
372 #else
373         dateTextStyle.color = (IsToday(day) && day.focused) ? focusedDayColor_
374                                : IsToday(day)                ? todayDayColor_
375                                : IsOffDay(day)               ? weekendDayColor_
376                                                              : dayColor_;
377         lunarTextStyle.color =
378             (IsToday(day) && day.focused) ? focusedLunarColor_
379             : IsToday(day)                ? todayLunarColor_
380                            : (day.markLunarDay ? markLunarColor_ : (IsOffDay(day) ? weekendLunarColor_ : lunarColor_));
381 #endif
382     }
383 }
384 
SetCalendarPickerDayTextStyle(RSTextStyle & dateTextStyle,const CalendarDay & day)385 void CalendarPaintMethod::SetCalendarPickerDayTextStyle(RSTextStyle& dateTextStyle, const CalendarDay& day)
386 {
387     if (day.month.month != currentMonth_.month) {
388 #ifndef USE_GRAPHIC_TEXT_GINE
389         dateTextStyle.color_ = textNonCurrentMonthColor_;
390 #else
391         dateTextStyle.color = textNonCurrentMonthColor_;
392 #endif
393     } else {
394         if (IsToday(day)) {
395 #ifndef USE_GRAPHIC_TEXT_GINE
396             dateTextStyle.color_ = day.isSelected ? textSelectedDayColor_ : textCurrentDayColor_;
397 #else
398             dateTextStyle.color = day.isSelected ? textSelectedDayColor_ : textCurrentDayColor_;
399 #endif
400         } else {
401 #ifndef USE_GRAPHIC_TEXT_GINE
402             dateTextStyle.color_ = textCurrentMonthColor_;
403 #else
404             dateTextStyle.color = textCurrentMonthColor_;
405 #endif
406         }
407     }
408 }
409 
SetOffWorkTextStyle(RSTextStyle & offWorkTextStyle,const CalendarDay & day) const410 void CalendarPaintMethod::SetOffWorkTextStyle(RSTextStyle& offWorkTextStyle, const CalendarDay& day) const
411 {
412     // Paint off or work mark value.
413 #ifndef USE_GRAPHIC_TEXT_GINE
414     offWorkTextStyle.fontWeight_ = static_cast<RSFontWeight>(workStateFontWeight_);
415     offWorkTextStyle.locale_ = Localization::GetInstance()->GetFontLocale();
416 
417     if (!appFontFamilies_.empty()) {
418         offWorkTextStyle.fontFamilies_ = appFontFamilies_;
419     }
420 #else
421     offWorkTextStyle.fontWeight = static_cast<RSFontWeight>(workStateFontWeight_);
422     offWorkTextStyle.locale = Localization::GetInstance()->GetFontLocale();
423 
424     if (!appFontFamilies_.empty()) {
425         offWorkTextStyle.fontFamilies = appFontFamilies_;
426     }
427 #endif
428     if (day.month.month == currentMonth_.month) {
429         if (day.dayMark == "work") {
430 #ifndef USE_GRAPHIC_TEXT_GINE
431             offWorkTextStyle.fontSize_ = workDayMarkSize_;
432             offWorkTextStyle.color_ = workDayMarkColor_;
433 #else
434             offWorkTextStyle.fontSize = workDayMarkSize_;
435             offWorkTextStyle.color = workDayMarkColor_;
436 #endif
437         } else if (day.dayMark == "off") {
438 #ifndef USE_GRAPHIC_TEXT_GINE
439             offWorkTextStyle.fontSize_ = offDayMarkSize_;
440             offWorkTextStyle.color_ = offDayMarkColor_;
441 #else
442             offWorkTextStyle.fontSize = offDayMarkSize_;
443             offWorkTextStyle.color = offDayMarkColor_;
444 #endif
445         }
446     } else {
447         if (day.dayMark == "work") {
448 #ifndef USE_GRAPHIC_TEXT_GINE
449             offWorkTextStyle.fontSize_ = workDayMarkSize_;
450             offWorkTextStyle.color_ =
451                 RSColor(nonCurrentMonthWorkDayMarkColor_.GetRed(), nonCurrentMonthWorkDayMarkColor_.GetGreen(),
452                     nonCurrentMonthWorkDayMarkColor_.GetBlue(), WEEKEND_TRANSPARENT);
453 #else
454             offWorkTextStyle.fontSize = workDayMarkSize_;
455             offWorkTextStyle.color =
456                 RSColor(nonCurrentMonthWorkDayMarkColor_.GetRed(), nonCurrentMonthWorkDayMarkColor_.GetGreen(),
457                     nonCurrentMonthWorkDayMarkColor_.GetBlue(), WEEKEND_TRANSPARENT);
458 #endif
459         } else if (day.dayMark == "off") {
460 #ifndef USE_GRAPHIC_TEXT_GINE
461             offWorkTextStyle.fontSize_ = offDayMarkSize_;
462             offWorkTextStyle.color_ =
463                 RSColor(nonCurrentMonthOffDayMarkColor_.GetRed(), nonCurrentMonthOffDayMarkColor_.GetGreen(),
464                     nonCurrentMonthOffDayMarkColor_.GetBlue(), WEEKEND_TRANSPARENT);
465 #else
466             offWorkTextStyle.fontSize = offDayMarkSize_;
467             offWorkTextStyle.color =
468                 RSColor(nonCurrentMonthOffDayMarkColor_.GetRed(), nonCurrentMonthOffDayMarkColor_.GetGreen(),
469                     nonCurrentMonthOffDayMarkColor_.GetBlue(), WEEKEND_TRANSPARENT);
470 #endif
471         }
472     }
473 
474     // If it is today and it is focused, workState color is same as focused day color.
475     if (IsToday(day) && day.focused) {
476 #ifndef USE_GRAPHIC_TEXT_GINE
477         offWorkTextStyle.color_ = focusedDayColor_;
478 #else
479         offWorkTextStyle.color = focusedDayColor_;
480 #endif
481     }
482 }
483 
PaintDay(RSCanvas & canvas,const Offset & offset,const CalendarDay & day,RSTextStyle & textStyle) const484 void CalendarPaintMethod::PaintDay(
485     RSCanvas& canvas, const Offset& offset, const CalendarDay& day, RSTextStyle& textStyle) const
486 {
487     // Paint day value.
488     Rect boxRect { offset.GetX(), offset.GetY(), dayWidth_, gregorianDayHeight_ };
489     Rect textRect;
490 
491     auto dayStr = std::to_string(day.day);
492     dayStr = Localization::GetInstance()->NumberFormat(day.day);
493     DrawCalendarText(&canvas, dayStr, textStyle, boxRect, textRect);
494 
495     // Paint off and work mark value.
496     if (!day.dayMark.empty() && showHoliday_) {
497         RSTextStyle workStateStyle;
498         boxRect = { textRect.GetOffset().GetX() + textRect.Width() - workStateHorizontalMovingDistance_,
499             textRect.GetOffset().GetY() + textRect.Height() - workStateVerticalMovingDistance_, workStateWidth_,
500             workStateWidth_ };
501         SetOffWorkTextStyle(workStateStyle, day);
502         DrawCalendarText(&canvas, day.dayMarkValue, workStateStyle, boxRect);
503     }
504 }
505 
PaintLunarDay(RSCanvas & canvas,const Offset & offset,const CalendarDay & day,const RSTextStyle & textStyle) const506 void CalendarPaintMethod::PaintLunarDay(
507     RSCanvas& canvas, const Offset& offset, const CalendarDay& day, const RSTextStyle& textStyle) const
508 {
509     Rect boxRect = { offset.GetX(), offset.GetY(), dayWidth_, lunarDayHeight_ };
510     DrawCalendarText(&canvas, day.lunarDay, textStyle, boxRect);
511 }
512 
DrawWeek(RSCanvas & canvas,const Offset & offset) const513 void CalendarPaintMethod::DrawWeek(RSCanvas& canvas, const Offset& offset) const
514 {
515     uint32_t totalWeek = weekNumbers_.size();
516     RSTextStyle weekTextStyle;
517 #ifndef USE_GRAPHIC_TEXT_GINE
518     weekTextStyle.color_ = weekColor_;
519     weekTextStyle.fontSize_ = weekFontSize_;
520     weekTextStyle.locale_ = Localization::GetInstance()->GetFontLocale();
521 
522     if (!appFontFamilies_.empty()) {
523         weekTextStyle.fontFamilies_ = appFontFamilies_;
524     }
525 #else
526     weekTextStyle.color = weekColor_;
527     weekTextStyle.fontSize = weekFontSize_;
528     weekTextStyle.locale = Localization::GetInstance()->GetFontLocale();
529 
530     if (!appFontFamilies_.empty()) {
531         weekTextStyle.fontFamilies = appFontFamilies_;
532     }
533 #endif
534     static const int32_t daysOfWeek = 7;
535 
536     auto startDayOfWeek = startOfWeek_;
537     for (uint32_t column = 0; column < totalWeek; column++) {
538         double x = textDirection_ == TextDirection::LTR ? column * (weekWidth_ + colSpace_)
539                                                         : (totalWeek - column - 1) * (weekWidth_ + colSpace_);
540         Offset weekNumberOffset = offset + Offset(x, topPadding_);
541         Rect boxRect { weekNumberOffset.GetX(), weekNumberOffset.GetY(), weekWidth_, weekHeight_ };
542         std::string newText { weekNumbers_[(startDayOfWeek + 1) % daysOfWeek] };
543         auto wText = StringUtils::ToWstring(newText);
544         if (wText.size() > TEXT_MAX_LENGTH) {
545             wText = wText.substr(0, WEEK_TEXT_END_INDEX);
546             newText = StringUtils::ToString(wText);
547         }
548         DrawCalendarText(&canvas, newText, weekTextStyle, boxRect);
549         ++startDayOfWeek;
550     }
551 }
552 
SetCalendarTheme(const RefPtr<CalendarPaintProperty> & paintProperty)553 void CalendarPaintMethod::SetCalendarTheme(const RefPtr<CalendarPaintProperty>& paintProperty)
554 {
555     auto pipelineContext = PipelineContext::GetCurrentContextSafelyWithCheck();
556     CHECK_NULL_VOID(pipelineContext);
557     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
558     CHECK_NULL_VOID(theme);
559 
560     auto fontManager = pipelineContext->GetFontManager();
561     if (fontManager && !(fontManager->GetAppCustomFont().empty())) {
562         appFontFamilies_ = Framework::ConvertStrToFontFamilies(fontManager->GetAppCustomFont());
563     }
564 
565     weekColor_ = ToRSColor(paintProperty->GetWeekColor().value_or(theme->GetCalendarTheme().weekColor));
566     dayColor_ = ToRSColor(paintProperty->GetDayColor().value_or(theme->GetCalendarTheme().dayColor));
567     lunarColor_ = ToRSColor(paintProperty->GetLunarColor().value_or(theme->GetCalendarTheme().lunarColor));
568     weekendDayColor_ =
569         ToRSColor(paintProperty->GetWeekendDayColor().value_or(theme->GetCalendarTheme().weekendDayColor));
570     weekendLunarColor_ =
571         ToRSColor(paintProperty->GetWeekendLunarColor().value_or(theme->GetCalendarTheme().weekendLunarColor));
572     nonCurrentMonthDayColor_ = ToRSColor(
573         paintProperty->GetNonCurrentMonthDayColor().value_or(theme->GetCalendarTheme().nonCurrentMonthDayColor));
574     nonCurrentMonthLunarColor_ = ToRSColor(
575         paintProperty->GetNonCurrentMonthLunarColor().value_or(theme->GetCalendarTheme().nonCurrentMonthLunarColor));
576     workDayMarkColor_ =
577         ToRSColor(paintProperty->GetWorkDayMarkColor().value_or(theme->GetCalendarTheme().workDayMarkColor));
578     offDayMarkColor_ =
579         ToRSColor(paintProperty->GetOffDayMarkColor().value_or(theme->GetCalendarTheme().offDayMarkColor));
580     nonCurrentMonthWorkDayMarkColor_ = ToRSColor(paintProperty->GetNonCurrentMonthWorkDayMarkColor().value_or(
581         theme->GetCalendarTheme().nonCurrentMonthWorkDayMarkColor));
582     nonCurrentMonthOffDayMarkColor_ = ToRSColor(paintProperty->GetNonCurrentMonthOffDayMarkColor().value_or(
583         theme->GetCalendarTheme().nonCurrentMonthOffDayMarkColor));
584     focusedDayColor_ =
585         ToRSColor(paintProperty->GetFocusedDayColor().value_or(theme->GetCalendarTheme().focusedDayColor));
586     focusedLunarColor_ =
587         ToRSColor(paintProperty->GetFocusedLunarColor().value_or(theme->GetCalendarTheme().focusedLunarColor));
588     focusedAreaBackgroundColor_ = ToRSColor(
589         paintProperty->GetFocusedAreaBackgroundColor().value_or(theme->GetCalendarTheme().focusedAreaBackgroundColor));
590     markLunarColor_ = ToRSColor(paintProperty->GetMarkLunarColor().value_or(theme->GetCalendarTheme().markLunarColor));
591 
592     todayDayColor_ = RSColor(theme->GetCalendarTheme().todayColor.GetValue());
593     todayLunarColor_ = RSColor(theme->GetCalendarTheme().todayLunarColor.GetValue());
594 
595     dayFontWeight_ = StringUtils::StringToFontWeight(theme->GetCalendarTheme().dayFontWeight);
596     lunarDayFontWeight_ = StringUtils::StringToFontWeight(theme->GetCalendarTheme().lunarDayFontWeight);
597     workStateFontWeight_ = StringUtils::StringToFontWeight(theme->GetCalendarTheme().workStateFontWeight);
598 
599     topPadding_ = isCalendarDialog_ ? 0.0 : theme->GetCalendarTheme().topPadding.ConvertToPx();
600     weekFontSize_ = paintProperty->GetWeekFontSize().value_or(theme->GetCalendarTheme().weekFontSize).ConvertToPx();
601     dayFontSize_ = paintProperty->GetDayFontSize().value_or(theme->GetCalendarTheme().dayFontSize).ConvertToPx();
602     lunarDayFontSize_ =
603         paintProperty->GetLunarDayFontSize().value_or(theme->GetCalendarTheme().lunarDayFontSize).ConvertToPx();
604     workDayMarkSize_ =
605         paintProperty->GetWorkDayMarkSize().value_or(theme->GetCalendarTheme().workDayMarkSize).ConvertToPx();
606     offDayMarkSize_ =
607         paintProperty->GetOffDayMarkSize().value_or(theme->GetCalendarTheme().offDayMarkSize).ConvertToPx();
608     focusedAreaRadius_ = paintProperty->GetFocusedAreaRadiusValue({}).ConvertToPx() <= 0
609                              ? theme->GetCalendarTheme().focusedAreaRadius.ConvertToPx()
610                              : paintProperty->GetFocusedAreaRadiusValue({}).ConvertToPx();
611 
612     weekHeight_ = paintProperty->GetWeekHeightValue({}).ConvertToPx() <= 0
613                       ? theme->GetCalendarTheme().weekHeight.ConvertToPx()
614                       : paintProperty->GetWeekHeightValue({}).ConvertToPx();
615     dayHeight_ = paintProperty->GetDayHeightValue({}).ConvertToPx() <= 0
616                      ? theme->GetCalendarTheme().dayHeight.ConvertToPx()
617                      : paintProperty->GetDayHeightValue({}).ConvertToPx();
618     weekWidth_ = paintProperty->GetWeekWidthValue({}).ConvertToPx() <= 0
619                      ? theme->GetCalendarTheme().weekWidth.ConvertToPx()
620                      : paintProperty->GetWeekWidthValue({}).ConvertToPx();
621     dayWidth_ = paintProperty->GetDayWidthValue({}).ConvertToPx() <= 0
622                     ? theme->GetCalendarTheme().dayWidth.ConvertToPx()
623                     : paintProperty->GetDayWidthValue({}).ConvertToPx();
624     weekAndDayRowSpace_ =
625         paintProperty->GetWeekAndDayRowSpace().value_or(theme->GetCalendarTheme().weekAndDayRowSpace).ConvertToPx();
626 
627     touchCircleStrokeWidth_ = theme->GetCalendarTheme().touchCircleStrokeWidth.ConvertToPx();
628 
629     colSpace_ = paintProperty->GetColSpaceValue({}).ConvertToPx() <= 0
630                     ? theme->GetCalendarTheme().colSpace.ConvertToPx()
631                     : paintProperty->GetColSpaceValue({}).ConvertToPx();
632     dailyFourRowSpace_ = NonPositive(paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx())
633                              ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
634                              : paintProperty->GetDailyFourRowSpaceValue({}).ConvertToPx();
635     dailyFiveRowSpace_ = paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx() <= 0
636                              ? theme->GetCalendarTheme().dailyFiveRowSpace.ConvertToPx()
637                              : paintProperty->GetDailyFiveRowSpaceValue({}).ConvertToPx();
638 
639     dailySixRowSpace_ = paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx() <= 0
640                             ? theme->GetCalendarTheme().dailySixRowSpace.ConvertToPx()
641                             : paintProperty->GetDailySixRowSpaceValue({}).ConvertToPx();
642 
643     gregorianDayHeight_ = paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx() <= 0
644                                    ? theme->GetCalendarTheme().gregorianCalendarHeight.ConvertToPx()
645                                    : paintProperty->GetGregorianCalendarHeightValue({}).ConvertToPx();
646 
647     lunarDayHeight_ = paintProperty->GetLunarHeight().value_or(theme->GetCalendarTheme().lunarHeight).ConvertToPx();
648 
649     gregorianDayYAxisOffset_ =
650         paintProperty->GetDayYAxisOffset().value_or(theme->GetCalendarTheme().dayYAxisOffset).ConvertToPx();
651     lunarDayYAxisOffset_ =
652         paintProperty->GetLunarDayYAxisOffset().value_or(theme->GetCalendarTheme().lunarDayYAxisOffset).ConvertToPx();
653 
654     workStateWidth_ = paintProperty->GetWorkStateWidthValue({}).ConvertToPx() <= 0
655                           ? theme->GetCalendarTheme().workStateWidth.ConvertToPx()
656                           : paintProperty->GetWorkStateWidthValue({}).ConvertToPx();
657 
658     workStateHorizontalMovingDistance_ = paintProperty->GetWorkStateHorizontalMovingDistance()
659                                              .value_or(theme->GetCalendarTheme().workStateHorizontalMovingDistance)
660                                              .ConvertToPx();
661     workStateVerticalMovingDistance_ = paintProperty->GetWorkStateVerticalMovingDistance()
662                                            .value_or(theme->GetCalendarTheme().workStateVerticalMovingDistance)
663                                            .ConvertToPx();
664     dayRadius_ = paintProperty->GetDayRadiusValue(theme->GetCalendarDayRadius()).ConvertToPx();
665     textNonCurrentMonthColor_ = ToRSColor(theme->GetTextNonCurrentMonthColor());
666     textSelectedDayColor_ = ToRSColor(theme->GetTextSelectedDayColor());
667     textCurrentDayColor_ = ToRSColor(theme->GetTextCurrentDayColor());
668     textCurrentMonthColor_ = ToRSColor(theme->GetTextCurrentMonthColor());
669     backgroundKeyFocusedColor_ = ToRSColor(theme->GetBackgroundKeyFocusedColor());
670     backgroundSelectedTodayColor_ = ToRSColor(theme->GetBackgroundSelectedTodayColor());
671     backgroundSelectedNotTodayColor_ = ToRSColor(theme->GetBackgroundSelectedNotTodayColor());
672     backgroundHoverColor_ = ToRSColor(theme->GetBackgroundHoverColor());
673     backgroundPressColor_ = ToRSColor(theme->GetBackgroundPressColor());
674 
675     auto fontSizeScale = pipelineContext->GetFontScale();
676     if (fontSizeScale < theme->GetCalendarPickerLargeScale() ||
677         Dimension(pipelineContext->GetRootHeight()).ConvertToVp() < DEVICE_HEIGHT_LIMIT) {
678         calendarDayKeyFocusedWidth_ = theme->GetCalendarDayKeyFocusedWidth().ConvertToPx();
679     } else {
680         calendarDayKeyFocusedWidth_ = theme->GetCalendarLargeDayKeyFocusedWidth().ConvertToPx();
681     }
682 
683     calendarDayKeyFocusedPenWidth_ = theme->GetCalendarDayKeyFocusedPenWidth().ConvertToPx();
684     if (paintProperty->HasShowLunar()) {
685         showLunar_ = paintProperty->GetShowLunarValue();
686     }
687     showHoliday_ = paintProperty->GetShowHolidayValue(true);
688     if (paintProperty->HasStartOfWeek()) {
689         startOfWeek_ = static_cast<int32_t>(paintProperty->GetStartOfWeekValue());
690     }
691     startOfWeek_ = static_cast<int32_t>(log2(startOfWeek_));
692     if (paintProperty->HasOffDays()) {
693         offDays_ = paintProperty->GetOffDaysValue();
694     }
695     currentMonth_.month = obtainedMonth_.month;
696 }
697 
IsToday(const CalendarDay & day) const698 bool CalendarPaintMethod::IsToday(const CalendarDay& day) const
699 {
700     auto today = calendarDay_;
701     return today.month == day.month && today.day == day.day;
702 }
703 
IsOffDay(const CalendarDay & dayInfo) const704 bool CalendarPaintMethod::IsOffDay(const CalendarDay& dayInfo) const
705 {
706     std::vector<std::string> days;
707     StringUtils::StringSplitter(offDays_, ',', days);
708     int32_t daysOfWeek = 7;
709     for (const auto& day : days) {
710         auto num = (StringUtils::StringToInt(day) + (daysOfWeek - static_cast<int32_t>(startOfWeek_))) % daysOfWeek;
711         if ((dayInfo.index % daysOfWeek) == num) {
712             return true;
713         }
714     }
715     return false;
716 }
717 } // namespace OHOS::Ace::NG
718