diff options
Diffstat (limited to 'layout/forms/nsGfxCheckboxControlFrame.cpp')
-rw-r--r-- | layout/forms/nsGfxCheckboxControlFrame.cpp | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/layout/forms/nsGfxCheckboxControlFrame.cpp b/layout/forms/nsGfxCheckboxControlFrame.cpp new file mode 100644 index 000000000..061c92349 --- /dev/null +++ b/layout/forms/nsGfxCheckboxControlFrame.cpp @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsGfxCheckboxControlFrame.h" + +#include "gfxUtils.h" +#include "mozilla/gfx/2D.h" +#include "nsIContent.h" +#include "nsCOMPtr.h" +#include "nsLayoutUtils.h" +#include "nsRenderingContext.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsDisplayList.h" +#include <algorithm> + +using namespace mozilla; +using namespace mozilla::gfx; + +static void +PaintCheckMark(nsIFrame* aFrame, + DrawTarget* aDrawTarget, + const nsRect& aDirtyRect, + nsPoint aPt) +{ + nsRect rect(aPt, aFrame->GetSize()); + rect.Deflate(aFrame->GetUsedBorderAndPadding()); + + // Points come from the coordinates on a 7X7 unit box centered at 0,0 + const int32_t checkPolygonX[] = { -3, -1, 3, 3, -1, -3 }; + const int32_t checkPolygonY[] = { -1, 1, -3, -1, 3, 1 }; + const int32_t checkNumPoints = sizeof(checkPolygonX) / sizeof(int32_t); + const int32_t checkSize = 9; // 2 units of padding on either side + // of the 7x7 unit checkmark + + // Scale the checkmark based on the smallest dimension + nscoord paintScale = std::min(rect.width, rect.height) / checkSize; + nsPoint paintCenter(rect.x + rect.width / 2, + rect.y + rect.height / 2); + + RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(); + nsPoint p = paintCenter + nsPoint(checkPolygonX[0] * paintScale, + checkPolygonY[0] * paintScale); + + int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); + builder->MoveTo(NSPointToPoint(p, appUnitsPerDevPixel)); + for (int32_t polyIndex = 1; polyIndex < checkNumPoints; polyIndex++) { + p = paintCenter + nsPoint(checkPolygonX[polyIndex] * paintScale, + checkPolygonY[polyIndex] * paintScale); + builder->LineTo(NSPointToPoint(p, appUnitsPerDevPixel)); + } + RefPtr<Path> path = builder->Finish(); + aDrawTarget->Fill(path, + ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor))); +} + +static void +PaintIndeterminateMark(nsIFrame* aFrame, + DrawTarget* aDrawTarget, + const nsRect& aDirtyRect, + nsPoint aPt) +{ + int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); + + nsRect rect(aPt, aFrame->GetSize()); + rect.Deflate(aFrame->GetUsedBorderAndPadding()); + rect.y += (rect.height - rect.height/4) / 2; + rect.height /= 4; + + Rect devPxRect = NSRectToSnappedRect(rect, appUnitsPerDevPixel, *aDrawTarget); + + aDrawTarget->FillRect( + devPxRect, ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor))); +} + +//------------------------------------------------------------ +nsIFrame* +NS_NewGfxCheckboxControlFrame(nsIPresShell* aPresShell, + nsStyleContext* aContext) +{ + return new (aPresShell) nsGfxCheckboxControlFrame(aContext); +} + +NS_IMPL_FRAMEARENA_HELPERS(nsGfxCheckboxControlFrame) + + +//------------------------------------------------------------ +// Initialize GFX-rendered state +nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame(nsStyleContext* aContext) +: nsFormControlFrame(aContext) +{ +} + +nsGfxCheckboxControlFrame::~nsGfxCheckboxControlFrame() +{ +} + +#ifdef ACCESSIBILITY +a11y::AccType +nsGfxCheckboxControlFrame::AccessibleType() +{ + return a11y::eHTMLCheckboxType; +} +#endif + +//------------------------------------------------------------ +void +nsGfxCheckboxControlFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + nsFormControlFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); + + // Get current checked state through content model. + if ((!IsChecked() && !IsIndeterminate()) || !IsVisibleForPainting(aBuilder)) + return; // we're not checked or not visible, nothing to paint. + + if (IsThemed()) + return; // No need to paint the checkmark. The theme will do it. + + aLists.Content()->AppendNewToTop(new (aBuilder) + nsDisplayGeneric(aBuilder, this, + IsIndeterminate() + ? PaintIndeterminateMark : PaintCheckMark, + "CheckedCheckbox", + nsDisplayItem::TYPE_CHECKED_CHECKBOX)); +} + +//------------------------------------------------------------ +bool +nsGfxCheckboxControlFrame::IsChecked() +{ + nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent)); + bool retval = false; + elem->GetChecked(&retval); + return retval; +} + +bool +nsGfxCheckboxControlFrame::IsIndeterminate() +{ + nsCOMPtr<nsIDOMHTMLInputElement> elem(do_QueryInterface(mContent)); + bool retval = false; + elem->GetIndeterminate(&retval); + return retval; +} |