PageRenderTime 485ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/hwui/ClipArea.cpp

http://github.com/android/platform_frameworks_base
C++ | 374 lines | 273 code | 56 blank | 45 comment | 37 complexity | f34d3bb81dc0fff7361a635b8839a2b4 MD5 | raw file
Possible License(s): BitTorrent-1.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, CC0-1.0
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "ClipArea.h"
  17. #include <SkPath.h>
  18. #include <limits>
  19. #include "Rect.h"
  20. namespace android {
  21. namespace uirenderer {
  22. static bool intersect(Rect& r, const Rect& r2) {
  23. bool hasIntersection = r.intersect(r2);
  24. if (!hasIntersection) {
  25. r.setEmpty();
  26. }
  27. return hasIntersection;
  28. }
  29. static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
  30. Vertex v;
  31. v.x = x;
  32. v.y = y;
  33. transform.mapPoint(v.x, v.y);
  34. transformedBounds.expandToCoverVertex(v.x, v.y);
  35. }
  36. Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
  37. const float kMinFloat = std::numeric_limits<float>::lowest();
  38. const float kMaxFloat = std::numeric_limits<float>::max();
  39. Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
  40. handlePoint(transformedBounds, transform, r.left, r.top);
  41. handlePoint(transformedBounds, transform, r.right, r.top);
  42. handlePoint(transformedBounds, transform, r.left, r.bottom);
  43. handlePoint(transformedBounds, transform, r.right, r.bottom);
  44. return transformedBounds;
  45. }
  46. /*
  47. * TransformedRectangle
  48. */
  49. TransformedRectangle::TransformedRectangle() {
  50. }
  51. TransformedRectangle::TransformedRectangle(const Rect& bounds,
  52. const Matrix4& transform)
  53. : mBounds(bounds)
  54. , mTransform(transform) {
  55. }
  56. bool TransformedRectangle::canSimplyIntersectWith(
  57. const TransformedRectangle& other) const {
  58. return mTransform == other.mTransform;
  59. }
  60. bool TransformedRectangle::intersectWith(const TransformedRectangle& other) {
  61. Rect translatedBounds(other.mBounds);
  62. return intersect(mBounds, translatedBounds);
  63. }
  64. bool TransformedRectangle::isEmpty() const {
  65. return mBounds.isEmpty();
  66. }
  67. /*
  68. * RectangleList
  69. */
  70. RectangleList::RectangleList()
  71. : mTransformedRectanglesCount(0) {
  72. }
  73. bool RectangleList::isEmpty() const {
  74. if (mTransformedRectanglesCount < 1) {
  75. return true;
  76. }
  77. for (int i = 0; i < mTransformedRectanglesCount; i++) {
  78. if (mTransformedRectangles[i].isEmpty()) {
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. int RectangleList::getTransformedRectanglesCount() const {
  85. return mTransformedRectanglesCount;
  86. }
  87. const TransformedRectangle& RectangleList::getTransformedRectangle(int i) const {
  88. return mTransformedRectangles[i];
  89. }
  90. void RectangleList::setEmpty() {
  91. mTransformedRectanglesCount = 0;
  92. }
  93. void RectangleList::set(const Rect& bounds, const Matrix4& transform) {
  94. mTransformedRectanglesCount = 1;
  95. mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
  96. }
  97. bool RectangleList::intersectWith(const Rect& bounds,
  98. const Matrix4& transform) {
  99. TransformedRectangle newRectangle(bounds, transform);
  100. // Try to find a rectangle with a compatible transformation
  101. int index = 0;
  102. for (; index < mTransformedRectanglesCount; index++) {
  103. TransformedRectangle& tr(mTransformedRectangles[index]);
  104. if (tr.canSimplyIntersectWith(newRectangle)) {
  105. tr.intersectWith(newRectangle);
  106. return true;
  107. }
  108. }
  109. // Add it to the list if there is room
  110. if (index < kMaxTransformedRectangles) {
  111. mTransformedRectangles[index] = newRectangle;
  112. mTransformedRectanglesCount += 1;
  113. return true;
  114. }
  115. // This rectangle list is full
  116. return false;
  117. }
  118. Rect RectangleList::calculateBounds() const {
  119. Rect bounds;
  120. for (int index = 0; index < mTransformedRectanglesCount; index++) {
  121. const TransformedRectangle& tr(mTransformedRectangles[index]);
  122. if (index == 0) {
  123. bounds = tr.transformedBounds();
  124. } else {
  125. bounds.intersect(tr.transformedBounds());
  126. }
  127. }
  128. return bounds;
  129. }
  130. static SkPath pathFromTransformedRectangle(const Rect& bounds,
  131. const Matrix4& transform) {
  132. SkPath rectPath;
  133. SkPath rectPathTransformed;
  134. rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
  135. SkMatrix skTransform;
  136. transform.copyTo(skTransform);
  137. rectPath.transform(skTransform, &rectPathTransformed);
  138. return rectPathTransformed;
  139. }
  140. SkRegion RectangleList::convertToRegion(const SkRegion& clip) const {
  141. SkRegion rectangleListAsRegion;
  142. for (int index = 0; index < mTransformedRectanglesCount; index++) {
  143. const TransformedRectangle& tr(mTransformedRectangles[index]);
  144. SkPath rectPathTransformed = pathFromTransformedRectangle(
  145. tr.getBounds(), tr.getTransform());
  146. if (index == 0) {
  147. rectangleListAsRegion.setPath(rectPathTransformed, clip);
  148. } else {
  149. SkRegion rectRegion;
  150. rectRegion.setPath(rectPathTransformed, clip);
  151. rectangleListAsRegion.op(rectRegion, SkRegion::kIntersect_Op);
  152. }
  153. }
  154. return rectangleListAsRegion;
  155. }
  156. /*
  157. * ClipArea
  158. */
  159. ClipArea::ClipArea()
  160. : mMode(kModeRectangle) {
  161. }
  162. /*
  163. * Interface
  164. */
  165. void ClipArea::setViewportDimensions(int width, int height) {
  166. mViewportBounds.set(0, 0, width, height);
  167. mClipRect = mViewportBounds;
  168. }
  169. void ClipArea::setEmpty() {
  170. mMode = kModeRectangle;
  171. mClipRect.setEmpty();
  172. mClipRegion.setEmpty();
  173. mRectangleList.setEmpty();
  174. }
  175. void ClipArea::setClip(float left, float top, float right, float bottom) {
  176. mMode = kModeRectangle;
  177. mClipRect.set(left, top, right, bottom);
  178. mClipRegion.setEmpty();
  179. }
  180. bool ClipArea::clipRectWithTransform(float left, float top, float right,
  181. float bottom, const mat4* transform, SkRegion::Op op) {
  182. Rect r(left, top, right, bottom);
  183. return clipRectWithTransform(r, transform, op);
  184. }
  185. bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
  186. SkRegion::Op op) {
  187. switch (mMode) {
  188. case kModeRectangle:
  189. return rectangleModeClipRectWithTransform(r, transform, op);
  190. case kModeRectangleList:
  191. return rectangleListModeClipRectWithTransform(r, transform, op);
  192. case kModeRegion:
  193. return regionModeClipRectWithTransform(r, transform, op);
  194. }
  195. return false;
  196. }
  197. bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
  198. enterRegionMode();
  199. mClipRegion.op(region, op);
  200. onClipRegionUpdated();
  201. return true;
  202. }
  203. bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
  204. SkRegion::Op op) {
  205. SkMatrix skTransform;
  206. transform->copyTo(skTransform);
  207. SkPath transformed;
  208. path.transform(skTransform, &transformed);
  209. SkRegion region;
  210. regionFromPath(transformed, region);
  211. return clipRegion(region, op);
  212. }
  213. /*
  214. * Rectangle mode
  215. */
  216. void ClipArea::enterRectangleMode() {
  217. // Entering rectangle mode discards any
  218. // existing clipping information from the other modes.
  219. // The only way this occurs is by a clip setting operation.
  220. mMode = kModeRectangle;
  221. }
  222. bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
  223. const mat4* transform, SkRegion::Op op) {
  224. if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
  225. mClipRect = r;
  226. transform->mapRect(mClipRect);
  227. return true;
  228. } else if (op != SkRegion::kIntersect_Op) {
  229. enterRegionMode();
  230. return regionModeClipRectWithTransform(r, transform, op);
  231. }
  232. if (transform->rectToRect()) {
  233. Rect transformed(r);
  234. transform->mapRect(transformed);
  235. bool hasIntersection = mClipRect.intersect(transformed);
  236. if (!hasIntersection) {
  237. mClipRect.setEmpty();
  238. }
  239. return true;
  240. }
  241. enterRectangleListMode();
  242. return rectangleListModeClipRectWithTransform(r, transform, op);
  243. }
  244. bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
  245. float right, float bottom, const mat4* transform, SkRegion::Op op) {
  246. Rect r(left, top, right, bottom);
  247. bool result = rectangleModeClipRectWithTransform(r, transform, op);
  248. mClipRect = mRectangleList.calculateBounds();
  249. return result;
  250. }
  251. /*
  252. * RectangleList mode implementation
  253. */
  254. void ClipArea::enterRectangleListMode() {
  255. // Is is only legal to enter rectangle list mode from
  256. // rectangle mode, since rectangle list mode cannot represent
  257. // all clip areas that can be represented by a region.
  258. ALOG_ASSERT(mMode == kModeRectangle);
  259. mMode = kModeRectangleList;
  260. mRectangleList.set(mClipRect, Matrix4::identity());
  261. }
  262. bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
  263. const mat4* transform, SkRegion::Op op) {
  264. if (op != SkRegion::kIntersect_Op
  265. || !mRectangleList.intersectWith(r, *transform)) {
  266. enterRegionMode();
  267. return regionModeClipRectWithTransform(r, transform, op);
  268. }
  269. return true;
  270. }
  271. bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
  272. float right, float bottom, const mat4* transform, SkRegion::Op op) {
  273. Rect r(left, top, right, bottom);
  274. return rectangleListModeClipRectWithTransform(r, transform, op);
  275. }
  276. /*
  277. * Region mode implementation
  278. */
  279. void ClipArea::enterRegionMode() {
  280. Mode oldMode = mMode;
  281. mMode = kModeRegion;
  282. if (oldMode != kModeRegion) {
  283. if (oldMode == kModeRectangle) {
  284. mClipRegion.setRect(mClipRect.left, mClipRect.top,
  285. mClipRect.right, mClipRect.bottom);
  286. } else {
  287. mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
  288. onClipRegionUpdated();
  289. }
  290. }
  291. }
  292. bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
  293. const mat4* transform, SkRegion::Op op) {
  294. SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
  295. SkRegion transformedRectRegion;
  296. regionFromPath(transformedRect, transformedRectRegion);
  297. mClipRegion.op(transformedRectRegion, op);
  298. onClipRegionUpdated();
  299. return true;
  300. }
  301. bool ClipArea::regionModeClipRectWithTransform(float left, float top,
  302. float right, float bottom, const mat4* transform, SkRegion::Op op) {
  303. return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
  304. transform, op);
  305. }
  306. void ClipArea::onClipRegionUpdated() {
  307. if (!mClipRegion.isEmpty()) {
  308. mClipRect.set(mClipRegion.getBounds());
  309. if (mClipRegion.isRect()) {
  310. mClipRegion.setEmpty();
  311. enterRectangleMode();
  312. }
  313. } else {
  314. mClipRect.setEmpty();
  315. }
  316. }
  317. } /* namespace uirenderer */
  318. } /* namespace android */