media_view_pip_raster.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "media/view/media_view_pip_raster.h"
  8. #include "ui/image/image_prepare.h"
  9. #include "ui/widgets/shadow.h"
  10. #include "ui/painter.h"
  11. #include "styles/style_calls.h" // st::callShadow.
  12. namespace Media::View {
  13. namespace {
  14. [[nodiscard]] Streaming::FrameRequest UnrotateRequest(
  15. const Streaming::FrameRequest &request,
  16. int rotation) {
  17. if (!rotation) {
  18. return request;
  19. }
  20. const auto unrotatedCorner = [&](int index) {
  21. using namespace Images;
  22. switch (index) {
  23. case kTopLeft:
  24. return (rotation == 90)
  25. ? kBottomLeft
  26. : (rotation == 180)
  27. ? kBottomRight
  28. : kTopRight;
  29. case kTopRight:
  30. return (rotation == 90)
  31. ? kTopLeft
  32. : (rotation == 180)
  33. ? kBottomLeft
  34. : kBottomRight;
  35. case kBottomRight:
  36. return (rotation == 90)
  37. ? kTopRight
  38. : (rotation == 180)
  39. ? kTopLeft
  40. : kBottomLeft;
  41. case kBottomLeft:
  42. return (rotation == 90)
  43. ? kBottomRight
  44. : (rotation == 180)
  45. ? kTopRight
  46. : kTopLeft;
  47. }
  48. Unexpected("Corner in rotateCorner.");
  49. };
  50. auto result = request;
  51. result.outer = FlipSizeByRotation(request.outer, rotation);
  52. result.resize = FlipSizeByRotation(request.resize, rotation);
  53. auto rounding = result.rounding;
  54. for (auto i = 0; i != 4; ++i) {
  55. result.rounding.p[unrotatedCorner(i)] = rounding.p[i];
  56. }
  57. return result;
  58. }
  59. } // namespace
  60. Pip::RendererSW::RendererSW(not_null<Pip*> owner)
  61. : _owner(owner)
  62. , _roundRect(ImageRoundRadius::Large, st::radialBg) {
  63. }
  64. void Pip::RendererSW::paintFallback(
  65. Painter &&p,
  66. const QRegion &clip,
  67. Ui::GL::Backend backend) {
  68. _p = &p;
  69. _clip = &clip;
  70. _clipOuter = clip.boundingRect();
  71. _owner->paint(this);
  72. _p = nullptr;
  73. _clip = nullptr;
  74. }
  75. void Pip::RendererSW::paintTransformedVideoFrame(
  76. ContentGeometry geometry) {
  77. paintTransformedImage(
  78. _owner->videoFrame(frameRequest(geometry)),
  79. geometry);
  80. }
  81. void Pip::RendererSW::paintTransformedStaticContent(
  82. const QImage &image,
  83. ContentGeometry geometry) {
  84. paintTransformedImage(
  85. staticContentByRequest(image, frameRequest(geometry)),
  86. geometry);
  87. }
  88. void Pip::RendererSW::paintFade(ContentGeometry geometry) const {
  89. using Part = RectPart;
  90. const auto sides = geometry.attached;
  91. const auto rounded = RectPart(0)
  92. | ((sides & (Part::Top | Part::Left)) ? Part(0) : Part::TopLeft)
  93. | ((sides & (Part::Top | Part::Right)) ? Part(0) : Part::TopRight)
  94. | ((sides & (Part::Bottom | Part::Right))
  95. ? Part(0)
  96. : Part::BottomRight)
  97. | ((sides & (Part::Bottom | Part::Left))
  98. ? Part(0)
  99. : Part::BottomLeft);
  100. _roundRect.paintSomeRounded(
  101. *_p,
  102. geometry.inner,
  103. rounded | Part::NoTopBottom | Part::Top | Part::Bottom);
  104. }
  105. void Pip::RendererSW::paintButtonsStart() {
  106. }
  107. void Pip::RendererSW::paintButton(
  108. const Button &button,
  109. int outerWidth,
  110. float64 shown,
  111. float64 over,
  112. const style::icon &icon,
  113. const style::icon &iconOver) {
  114. if (over < 1.) {
  115. _p->setOpacity(shown);
  116. icon.paint(*_p, button.icon.x(), button.icon.y(), outerWidth);
  117. }
  118. if (over > 0.) {
  119. _p->setOpacity(over * shown);
  120. iconOver.paint(*_p, button.icon.x(), button.icon.y(), outerWidth);
  121. }
  122. }
  123. Pip::FrameRequest Pip::RendererSW::frameRequest(
  124. ContentGeometry geometry) const {
  125. using namespace Images;
  126. auto result = FrameRequest();
  127. result.outer = geometry.inner.size() * style::DevicePixelRatio();
  128. result.resize = result.outer;
  129. result.rounding = CornersMaskRef(CornersMask(ImageRoundRadius::Large));
  130. if (geometry.attached & (RectPart::Top | RectPart::Left)) {
  131. result.rounding.p[kTopLeft] = nullptr;
  132. }
  133. if (geometry.attached & (RectPart::Top | RectPart::Right)) {
  134. result.rounding.p[kTopRight] = nullptr;
  135. }
  136. if (geometry.attached & (RectPart::Bottom | RectPart::Left)) {
  137. result.rounding.p[kBottomLeft] = nullptr;
  138. }
  139. if (geometry.attached & (RectPart::Bottom | RectPart::Right)) {
  140. result.rounding.p[kBottomRight] = nullptr;
  141. }
  142. return UnrotateRequest(result, geometry.rotation);
  143. }
  144. QImage Pip::RendererSW::staticContentByRequest(
  145. const QImage &image,
  146. const FrameRequest &request) {
  147. if (request.resize.isEmpty()) {
  148. return QImage();
  149. } else if (!_preparedStaticContent.isNull()
  150. && _preparedStaticRequest == request
  151. && image.cacheKey() == _preparedStaticKey) {
  152. return _preparedStaticContent;
  153. }
  154. _preparedStaticKey = image.cacheKey();
  155. _preparedStaticRequest = request;
  156. _preparedStaticContent = Images::Round(
  157. Images::Prepare(
  158. image,
  159. request.resize,
  160. { .outer = request.outer / style::DevicePixelRatio() }),
  161. request.rounding);
  162. return _preparedStaticContent;
  163. }
  164. void Pip::RendererSW::paintTransformedImage(
  165. const QImage &image,
  166. ContentGeometry geometry) {
  167. const auto rect = geometry.inner;
  168. const auto rotation = geometry.rotation;
  169. if (geometry.useTransparency) {
  170. Ui::Shadow::paint(*_p, rect, geometry.outer.width(), st::callShadow);
  171. }
  172. if (UsePainterRotation(rotation)) {
  173. if (rotation) {
  174. _p->save();
  175. _p->rotate(rotation);
  176. }
  177. PainterHighQualityEnabler hq(*_p);
  178. _p->drawImage(RotatedRect(rect, rotation), image);
  179. if (rotation) {
  180. _p->restore();
  181. }
  182. } else {
  183. _p->drawImage(rect, RotateFrameImage(image, rotation));
  184. }
  185. if (geometry.fade > 0) {
  186. _p->setOpacity(geometry.fade);
  187. paintFade(geometry);
  188. }
  189. }
  190. void Pip::RendererSW::paintRadialLoading(
  191. QRect inner,
  192. float64 controlsShown) {
  193. _owner->paintRadialLoadingContent(*_p, inner, st::radialFg->c);
  194. }
  195. void Pip::RendererSW::paintPlayback(QRect outer, float64 shown) {
  196. _owner->paintPlaybackContent(*_p, outer, shown);
  197. }
  198. void Pip::RendererSW::paintVolumeController(QRect outer, float64 shown) {
  199. _owner->paintVolumeControllerContent(*_p, outer, shown);
  200. }
  201. } // namespace Media::View