diff options
Diffstat (limited to 'base/gfx/platform_device_win.cc')
-rw-r--r-- | base/gfx/platform_device_win.cc | 482 |
1 files changed, 229 insertions, 253 deletions
diff --git a/base/gfx/platform_device_win.cc b/base/gfx/platform_device_win.cc index 92d8268..13d5031d 100644 --- a/base/gfx/platform_device_win.cc +++ b/base/gfx/platform_device_win.cc @@ -1,253 +1,229 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "base/gfx/platform_device_win.h" - -#include "base/logging.h" -#include "base/gfx/skia_utils.h" -#include "SkMatrix.h" -#include "SkPath.h" -#include "SkRegion.h" -#include "SkUtils.h" - -namespace gfx { - -PlatformDeviceWin::PlatformDeviceWin(const SkBitmap& bitmap) - : SkDevice(bitmap) { -} - -// static -void PlatformDeviceWin::InitializeDC(HDC context) { - // Enables world transformation. - // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the - // counterclockwise direction in logical space. This is equivalent to the - // statement that, in the GM_ADVANCED graphics mode, both arc control points - // and arcs themselves fully respect the device context's world-to-device - // transformation. - BOOL res = SetGraphicsMode(context, GM_ADVANCED); - DCHECK_NE(res, 0); - - // Enables dithering. - res = SetStretchBltMode(context, HALFTONE); - DCHECK_NE(res, 0); - // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called - // right after. - res = SetBrushOrgEx(context, 0, 0, NULL); - DCHECK_NE(res, 0); - - // Sets up default orientation. - res = SetArcDirection(context, AD_CLOCKWISE); - DCHECK_NE(res, 0); - - // Sets up default colors. - res = SetBkColor(context, RGB(255, 255, 255)); - DCHECK_NE(res, CLR_INVALID); - res = SetTextColor(context, RGB(0, 0, 0)); - DCHECK_NE(res, CLR_INVALID); - res = SetDCBrushColor(context, RGB(255, 255, 255)); - DCHECK_NE(res, CLR_INVALID); - res = SetDCPenColor(context, RGB(0, 0, 0)); - DCHECK_NE(res, CLR_INVALID); - - // Sets up default transparency. - res = SetBkMode(context, OPAQUE); - DCHECK_NE(res, 0); - res = SetROP2(context, R2_COPYPEN); - DCHECK_NE(res, 0); -} - -// static -void PlatformDeviceWin::LoadPathToDC(HDC context, const SkPath& path) { - switch (path.getFillType()) { - case SkPath::kWinding_FillType: { - int res = SetPolyFillMode(context, WINDING); - DCHECK(res != 0); - break; - } - case SkPath::kEvenOdd_FillType: { - int res = SetPolyFillMode(context, ALTERNATE); - DCHECK(res != 0); - break; - } - default: { - NOTREACHED(); - break; - } - } - BOOL res = BeginPath(context); - DCHECK(res != 0); - - CubicPaths paths; - if (!SkPathToCubicPaths(&paths, path)) - return; - - std::vector<POINT> points; - for (CubicPaths::const_iterator path(paths.begin()); path != paths.end(); - ++path) { - if (!path->size()) - continue; - // DCHECK_EQ(points.size() % 4, 0); - points.resize(0); - points.reserve(path->size() * 3 / 4 + 1); - points.push_back(SkPointToPOINT(path->front().p[0])); - for (CubicPath::const_iterator point(path->begin()); point != path->end(); - ++point) { - // Never add point->p[0] - points.push_back(SkPointToPOINT(point->p[1])); - points.push_back(SkPointToPOINT(point->p[2])); - points.push_back(SkPointToPOINT(point->p[3])); - } - DCHECK_EQ((points.size() - 1) % 3, 0); - // This is slightly inefficient since all straight line and quadratic lines - // are "upgraded" to a cubic line. - // TODO(maruel): http://b/1147346 We should use - // PolyDraw/PolyBezier/Polyline whenever possible. - res = PolyBezier(context, &points.front(), - static_cast<DWORD>(points.size())); - DCHECK_NE(res, 0); - if (res == 0) - break; - } - if (res == 0) { - // Make sure the path is discarded. - AbortPath(context); - } else { - res = EndPath(context); - DCHECK(res != 0); - } -} - -// static -void PlatformDeviceWin::LoadTransformToDC(HDC dc, const SkMatrix& matrix) { - XFORM xf; - xf.eM11 = matrix[SkMatrix::kMScaleX]; - xf.eM21 = matrix[SkMatrix::kMSkewX]; - xf.eDx = matrix[SkMatrix::kMTransX]; - xf.eM12 = matrix[SkMatrix::kMSkewY]; - xf.eM22 = matrix[SkMatrix::kMScaleY]; - xf.eDy = matrix[SkMatrix::kMTransY]; - SetWorldTransform(dc, &xf); -} - -// static -bool PlatformDeviceWin::SkPathToCubicPaths(CubicPaths* paths, - const SkPath& skpath) { - paths->clear(); - CubicPath* current_path = NULL; - SkPoint current_points[4]; - CubicPoints points_to_add; - SkPath::Iter iter(skpath, false); - for (SkPath::Verb verb = iter.next(current_points); - verb != SkPath::kDone_Verb; - verb = iter.next(current_points)) { - switch (verb) { - case SkPath::kMove_Verb: { // iter.next returns 1 point - // Ignores it since the point is copied in the next operation. See - // SkPath::Iter::next() for reference. - paths->push_back(CubicPath()); - current_path = &paths->back(); - // Skip point addition. - continue; - } - case SkPath::kLine_Verb: { // iter.next returns 2 points - points_to_add.p[0] = current_points[0]; - points_to_add.p[1] = current_points[0]; - points_to_add.p[2] = current_points[1]; - points_to_add.p[3] = current_points[1]; - break; - } - case SkPath::kQuad_Verb: { // iter.next returns 3 points - points_to_add.p[0] = current_points[0]; - points_to_add.p[1] = current_points[1]; - points_to_add.p[2] = current_points[2]; - points_to_add.p[3] = current_points[2]; - break; - } - case SkPath::kCubic_Verb: { // iter.next returns 4 points - points_to_add.p[0] = current_points[0]; - points_to_add.p[1] = current_points[1]; - points_to_add.p[2] = current_points[2]; - points_to_add.p[3] = current_points[3]; - break; - } - case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point) - paths->push_back(CubicPath()); - current_path = &paths->back(); - continue; - } - case SkPath::kDone_Verb: // iter.next returns 0 points - default: { - current_path = NULL; - // Will return false. - break; - } - } - DCHECK(current_path); - if (!current_path) { - paths->clear(); - return false; - } - current_path->push_back(points_to_add); - } - return true; -} - -// static -void PlatformDeviceWin::LoadClippingRegionToDC(HDC context, - const SkRegion& region, - const SkMatrix& transformation) { - HRGN hrgn; - if (region.isEmpty()) { - // region can be empty, in which case everything will be clipped. - hrgn = CreateRectRgn(0, 0, 0, 0); - } else if (region.isRect()) { - // Do the transformation. - SkRect rect; - rect.set(region.getBounds()); - transformation.mapRect(&rect); - SkIRect irect; - rect.round(&irect); - hrgn = CreateRectRgnIndirect(&SkIRectToRECT(irect)); - } else { - // It is complex. - SkPath path; - region.getBoundaryPath(&path); - // Clip. Note that windows clipping regions are not affected by the - // transform so apply it manually. - path.transform(transformation); - LoadPathToDC(context, path); - hrgn = PathToRegion(context); - } - int result = SelectClipRgn(context, hrgn); - DCHECK_NE(result, ERROR); - result = DeleteObject(hrgn); - DCHECK_NE(result, 0); -} - -} // namespace gfx +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/gfx/platform_device_win.h"
+
+#include "base/logging.h"
+#include "base/gfx/skia_utils.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkUtils.h"
+
+namespace gfx {
+
+PlatformDeviceWin::PlatformDeviceWin(const SkBitmap& bitmap)
+ : SkDevice(bitmap) {
+}
+
+// static
+void PlatformDeviceWin::InitializeDC(HDC context) {
+ // Enables world transformation.
+ // If the GM_ADVANCED graphics mode is set, GDI always draws arcs in the
+ // counterclockwise direction in logical space. This is equivalent to the
+ // statement that, in the GM_ADVANCED graphics mode, both arc control points
+ // and arcs themselves fully respect the device context's world-to-device
+ // transformation.
+ BOOL res = SetGraphicsMode(context, GM_ADVANCED);
+ DCHECK_NE(res, 0);
+
+ // Enables dithering.
+ res = SetStretchBltMode(context, HALFTONE);
+ DCHECK_NE(res, 0);
+ // As per SetStretchBltMode() documentation, SetBrushOrgEx() must be called
+ // right after.
+ res = SetBrushOrgEx(context, 0, 0, NULL);
+ DCHECK_NE(res, 0);
+
+ // Sets up default orientation.
+ res = SetArcDirection(context, AD_CLOCKWISE);
+ DCHECK_NE(res, 0);
+
+ // Sets up default colors.
+ res = SetBkColor(context, RGB(255, 255, 255));
+ DCHECK_NE(res, CLR_INVALID);
+ res = SetTextColor(context, RGB(0, 0, 0));
+ DCHECK_NE(res, CLR_INVALID);
+ res = SetDCBrushColor(context, RGB(255, 255, 255));
+ DCHECK_NE(res, CLR_INVALID);
+ res = SetDCPenColor(context, RGB(0, 0, 0));
+ DCHECK_NE(res, CLR_INVALID);
+
+ // Sets up default transparency.
+ res = SetBkMode(context, OPAQUE);
+ DCHECK_NE(res, 0);
+ res = SetROP2(context, R2_COPYPEN);
+ DCHECK_NE(res, 0);
+}
+
+// static
+void PlatformDeviceWin::LoadPathToDC(HDC context, const SkPath& path) {
+ switch (path.getFillType()) {
+ case SkPath::kWinding_FillType: {
+ int res = SetPolyFillMode(context, WINDING);
+ DCHECK(res != 0);
+ break;
+ }
+ case SkPath::kEvenOdd_FillType: {
+ int res = SetPolyFillMode(context, ALTERNATE);
+ DCHECK(res != 0);
+ break;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+ BOOL res = BeginPath(context);
+ DCHECK(res != 0);
+
+ CubicPaths paths;
+ if (!SkPathToCubicPaths(&paths, path))
+ return;
+
+ std::vector<POINT> points;
+ for (CubicPaths::const_iterator path(paths.begin()); path != paths.end();
+ ++path) {
+ if (!path->size())
+ continue;
+ // DCHECK_EQ(points.size() % 4, 0);
+ points.resize(0);
+ points.reserve(path->size() * 3 / 4 + 1);
+ points.push_back(SkPointToPOINT(path->front().p[0]));
+ for (CubicPath::const_iterator point(path->begin()); point != path->end();
+ ++point) {
+ // Never add point->p[0]
+ points.push_back(SkPointToPOINT(point->p[1]));
+ points.push_back(SkPointToPOINT(point->p[2]));
+ points.push_back(SkPointToPOINT(point->p[3]));
+ }
+ DCHECK_EQ((points.size() - 1) % 3, 0);
+ // This is slightly inefficient since all straight line and quadratic lines
+ // are "upgraded" to a cubic line.
+ // TODO(maruel): http://b/1147346 We should use
+ // PolyDraw/PolyBezier/Polyline whenever possible.
+ res = PolyBezier(context, &points.front(),
+ static_cast<DWORD>(points.size()));
+ DCHECK_NE(res, 0);
+ if (res == 0)
+ break;
+ }
+ if (res == 0) {
+ // Make sure the path is discarded.
+ AbortPath(context);
+ } else {
+ res = EndPath(context);
+ DCHECK(res != 0);
+ }
+}
+
+// static
+void PlatformDeviceWin::LoadTransformToDC(HDC dc, const SkMatrix& matrix) {
+ XFORM xf;
+ xf.eM11 = matrix[SkMatrix::kMScaleX];
+ xf.eM21 = matrix[SkMatrix::kMSkewX];
+ xf.eDx = matrix[SkMatrix::kMTransX];
+ xf.eM12 = matrix[SkMatrix::kMSkewY];
+ xf.eM22 = matrix[SkMatrix::kMScaleY];
+ xf.eDy = matrix[SkMatrix::kMTransY];
+ SetWorldTransform(dc, &xf);
+}
+
+// static
+bool PlatformDeviceWin::SkPathToCubicPaths(CubicPaths* paths,
+ const SkPath& skpath) {
+ paths->clear();
+ CubicPath* current_path = NULL;
+ SkPoint current_points[4];
+ CubicPoints points_to_add;
+ SkPath::Iter iter(skpath, false);
+ for (SkPath::Verb verb = iter.next(current_points);
+ verb != SkPath::kDone_Verb;
+ verb = iter.next(current_points)) {
+ switch (verb) {
+ case SkPath::kMove_Verb: { // iter.next returns 1 point
+ // Ignores it since the point is copied in the next operation. See
+ // SkPath::Iter::next() for reference.
+ paths->push_back(CubicPath());
+ current_path = &paths->back();
+ // Skip point addition.
+ continue;
+ }
+ case SkPath::kLine_Verb: { // iter.next returns 2 points
+ points_to_add.p[0] = current_points[0];
+ points_to_add.p[1] = current_points[0];
+ points_to_add.p[2] = current_points[1];
+ points_to_add.p[3] = current_points[1];
+ break;
+ }
+ case SkPath::kQuad_Verb: { // iter.next returns 3 points
+ points_to_add.p[0] = current_points[0];
+ points_to_add.p[1] = current_points[1];
+ points_to_add.p[2] = current_points[2];
+ points_to_add.p[3] = current_points[2];
+ break;
+ }
+ case SkPath::kCubic_Verb: { // iter.next returns 4 points
+ points_to_add.p[0] = current_points[0];
+ points_to_add.p[1] = current_points[1];
+ points_to_add.p[2] = current_points[2];
+ points_to_add.p[3] = current_points[3];
+ break;
+ }
+ case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
+ paths->push_back(CubicPath());
+ current_path = &paths->back();
+ continue;
+ }
+ case SkPath::kDone_Verb: // iter.next returns 0 points
+ default: {
+ current_path = NULL;
+ // Will return false.
+ break;
+ }
+ }
+ DCHECK(current_path);
+ if (!current_path) {
+ paths->clear();
+ return false;
+ }
+ current_path->push_back(points_to_add);
+ }
+ return true;
+}
+
+// static
+void PlatformDeviceWin::LoadClippingRegionToDC(HDC context,
+ const SkRegion& region,
+ const SkMatrix& transformation) {
+ HRGN hrgn;
+ if (region.isEmpty()) {
+ // region can be empty, in which case everything will be clipped.
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ } else if (region.isRect()) {
+ // Do the transformation.
+ SkRect rect;
+ rect.set(region.getBounds());
+ transformation.mapRect(&rect);
+ SkIRect irect;
+ rect.round(&irect);
+ hrgn = CreateRectRgnIndirect(&SkIRectToRECT(irect));
+ } else {
+ // It is complex.
+ SkPath path;
+ region.getBoundaryPath(&path);
+ // Clip. Note that windows clipping regions are not affected by the
+ // transform so apply it manually.
+ path.transform(transformation);
+ LoadPathToDC(context, path);
+ hrgn = PathToRegion(context);
+ }
+ int result = SelectClipRgn(context, hrgn);
+ DCHECK_NE(result, ERROR);
+ result = DeleteObject(hrgn);
+ DCHECK_NE(result, 0);
+}
+
+} // namespace gfx
+
|