/* * * Copyright 2019, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include namespace teeui { ConvexObject<4> makeSquareAtOffset(const PxPoint& offset, const pxs& sideLength) { return ConvexObject<4>({offset, offset + PxPoint{sideLength, .0}, offset + PxPoint{sideLength, sideLength}, offset + PxPoint{.0, sideLength}}); } Error ButtonImpl::draw(const PixelDrawer& drawPixel, const Box& bounds, const ConvexObjectInfo* coBegin, const ConvexObjectInfo* coEnd) { using intpxs = Coordinate; Box intBounds(bounds); auto drawPixelBoundsEnforced = [&](uint32_t x, uint32_t y, Color color) -> Error { if (!intBounds.contains(Point(x, y))) { TEEUI_LOG << "Bounds: " << bounds << " Pixel: " << Point(x, y) << ENDL; return Error::OutOfBoundsDrawing; } return drawPixel(x, y, color); }; auto drawBox = [&](const Box& box, Color c) -> Error { for (int y = 0; y < box.h().count(); ++y) { for (int x = 0; x < box.w().count(); ++x) { if (auto error = drawPixel(box.x().count() + x, box.y().count() + y, c)) { return error; } } } return Error::OK; }; #ifdef DRAW_DEBUG_MARKERS auto drawDebugBox = [&](const Box& box, Color c) { drawBox(box, (c & 0xffffff) | 0x40000000); }; drawDebugBox(intBounds, 0xff); #endif intpxs intRadius = radius_.count(); TEEUI_LOG << intBounds << ENDL; auto drawCorner = [&, this](intpxs right, intpxs bottom) -> Error { Box cBounds(intBounds.x(), intBounds.y(), intRadius, intRadius); cBounds.translateSelf(Point(right * (intBounds.w() - intRadius), bottom * (intBounds.h() - intRadius))); auto center = Point((intpxs(1) - right) * intRadius, (intpxs(1) - bottom) * intRadius); center += cBounds.topLeft(); center -= Point(.5, .5); TEEUI_LOG << "Radius: " << intRadius << " cBounds: " << cBounds << " center: " << center << ENDL; for (int y = 0; y < cBounds.h().count(); ++y) { for (int x = 0; x < cBounds.w().count(); ++x) { auto pos = Point(cBounds.x().count() + x, cBounds.y().count() + y); auto color = drawCirclePoint(center, intRadius, pos, color_); if (auto error = drawPixelBoundsEnforced(pos.x().count(), pos.y().count(), color)) { return error; } } } return Error::OK; }; if (roundTopLeft_) { if (auto error = drawCorner(0, 0)) return error; } else { if (auto error = drawBox( Box(0, 0, intRadius, intRadius).translate(intBounds.topLeft()), color_)) { return error; } } if (roundTopRight_) { if (auto error = drawCorner(1, 0)) return error; } else { if (auto error = drawBox(Box(intBounds.w() - intRadius, 0, intRadius, intRadius) .translate(intBounds.topLeft()), color_)) { return error; } } if (roundBottomLeft_) { if (auto error = drawCorner(0, 1)) return error; } else { if (auto error = drawBox(Box(0, intBounds.h() - intRadius, intRadius, intRadius) .translate(intBounds.topLeft()), color_)) { return error; } } if (roundBottomRight_) { if (auto error = drawCorner(1, 1)) return error; } else { if (auto error = drawBox(Box(intBounds.w() - intRadius, intBounds.h() - intRadius, intRadius, intRadius) .translate(intBounds.topLeft()), color_)) { return error; } } auto centerbox = Box(intRadius, intRadius, intBounds.w() - intRadius - intRadius, intBounds.h() - intRadius - intRadius) .translate(intBounds.topLeft()); if (auto error = drawBox(centerbox, color_)) return error; if (auto error = drawBox(Box(0, intRadius, intRadius, intBounds.h() - intRadius - intRadius) .translate(intBounds.topLeft()), color_)) { return error; } if (auto error = drawBox(Box(intRadius, 0, intBounds.w() - intRadius - intRadius, intRadius) .translate(intBounds.topLeft()), color_)) { return error; } if (auto error = drawBox(Box(intBounds.w() - intRadius, intRadius, intRadius, intBounds.h() - intRadius - intRadius) .translate(intBounds.topLeft()), color_)) { return error; } if (auto error = drawBox(Box(intRadius, intBounds.h() - intRadius, intBounds.w() - intRadius - intRadius, intRadius) .translate(intBounds.topLeft()), color_)) { return error; } bool hasCOs = coBegin != coEnd; if (hasCOs) { Box coBBox = Box::boundingBox(coBegin->begin, coBegin->end); for (const auto& co : makeRange(coBegin + 1, coEnd)) { coBBox = coBBox.merge(co.begin, co.end); } auto start = PxPoint{bounds.w() - coBBox.w(), bounds.h() - coBBox.h()} / pxs(2.0); start += bounds.topLeft(); Box intBBox(start.x().floor(), start.y().floor(), 0, 0); intBBox = intBBox.merge( Point{(start.x() + coBBox.w()).ceil(), (start.y() + coBBox.h()).ceil()}); TEEUI_LOG << "coBBox: " << coBBox << ENDL; TEEUI_LOG << "intBBox: " << intBBox << ENDL; for (int64_t y = 0; y < intBBox.h().count(); ++y) { for (int64_t x = 0; x < intBBox.w().count(); ++x) { PxPoint offset = coBBox.topLeft() + PxPoint{x, y}; // The pixel is a square of width and height 1.0 auto thePixel = makeSquareAtOffset(offset, 1.0); TEEUI_LOG << thePixel << ENDL; pxs areaCovered = 0.0; for (const auto& co : makeRange(coBegin, coEnd)) { auto coveredRegion = thePixel.intersect<10>(co.begin, co.end); if (coveredRegion) areaCovered += coveredRegion->area(); TEEUI_LOG << " region: " << (bool)coveredRegion << " area: " << areaCovered; } TEEUI_LOG << ENDL; if (areaCovered > 1.0) areaCovered = 1.0; TEEUI_LOG << "x: " << x << " y: " << y << " area: " << areaCovered << ENDL; uint32_t intensity = 0xff * areaCovered.count(); if (auto error = drawPixelBoundsEnforced(intBBox.x().count() + x, intBBox.y().count() + y, intensity << 24 | (0xffffff & convexObjectColor_))) return error; } } } return Error::OK; } } // namespace teeui