summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-31 23:46:24 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-10-31 23:46:24 +0000
commit3bc09dd258189832bc75cb324e1bd6347c0a40de (patch)
tree46efd46dbbc942c6a94864f3647ad7352590ea10
parent6cd5bfff0526b34183e4a5508920b11515e4461b (diff)
downloadchromium_src-3bc09dd258189832bc75cb324e1bd6347c0a40de.zip
chromium_src-3bc09dd258189832bc75cb324e1bd6347c0a40de.tar.gz
chromium_src-3bc09dd258189832bc75cb324e1bd6347c0a40de.tar.bz2
Factor out text, theme, and icon stuff out of PlatformContextSkia back to the original platform-specific files.
Review URL: http://codereview.chromium.org/8982 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@4347 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--webkit/port/platform/graphics/FontWin.cpp128
-rw-r--r--webkit/port/platform/graphics/IconWin.cpp7
-rw-r--r--webkit/port/platform/graphics/ImageSkia.cpp244
-rw-r--r--webkit/port/platform/graphics/PlatformContextSkia.cpp370
-rw-r--r--webkit/port/platform/graphics/PlatformContextSkia.h89
-rw-r--r--webkit/port/rendering/RenderThemeWin.cpp87
6 files changed, 399 insertions, 526 deletions
diff --git a/webkit/port/platform/graphics/FontWin.cpp b/webkit/port/platform/graphics/FontWin.cpp
index 9bd5a7a..0166763 100644
--- a/webkit/port/platform/graphics/FontWin.cpp
+++ b/webkit/port/platform/graphics/FontWin.cpp
@@ -33,6 +33,7 @@
#include "UniscribeStateTextRun.h"
#include "base/gfx/platform_canvas_win.h"
+#include "base/gfx/skia_utils.h"
#include "graphics/SkiaUtils.h"
#include "webkit/glue/webkit_glue.h"
@@ -53,6 +54,24 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
// Default size for the buffer. It should be enough for most of cases.
const int kDefaultBufferLength = 256;
+ SkColor color = context->fillColor();
+ unsigned char alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha)
+ return;
+
+ // Set up our graphics context.
+ HDC hdc = context->canvas()->beginPlatformPaint();
+ HGDIOBJ oldFont = SelectObject(hdc, font->platformData().hfont());
+
+ // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
+ // Enforce non-transparent color.
+ color = SkColorSetRGB(SkColorGetR(color),
+ SkColorGetG(color),
+ SkColorGetB(color));
+ SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
+ SetBkMode(hdc, TRANSPARENT);
+
// Windows needs the characters and the advances in nice contiguous
// buffers, which we build here.
Vector<WORD, kDefaultBufferLength> glyphs;
@@ -63,48 +82,52 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext,
// lowest-level text output function on Windows, there should be little
// penalty for splitting up the text. On the other hand, the buffer cannot
// be bigger than 4094 or the function will fail.
- int glyph_index = 0;
- int chunk_x = 0; // x offset of this span from the point
- while (glyph_index < numGlyphs) {
- // how many chars will be in this chunk?
- int cur_len = std::min(kMaxBufferLength, numGlyphs - glyph_index);
-
- glyphs.resize(cur_len);
- advances.resize(cur_len);
-
- int cur_width = 0;
- for (int i = 0; i < cur_len; ++i, ++glyph_index) {
- glyphs[i] = glyphBuffer.glyphAt(from + glyph_index);
- advances[i] = static_cast<int>(glyphBuffer.advanceAt(from +
- glyph_index));
- cur_width += advances[i];
- }
-
- // the 'point' represents the baseline, so we need to move it up to the
- // top of the bounding square by subtracting the ascent
- SkPoint origin2 = point;
- origin2.fY -= font->ascent();
- origin2.fX += chunk_x;
-
- bool success = false;
- for (int executions = 0; executions < 2; ++executions) {
- success = context->paintText(font->platformData().hfont(),
- cur_len,
- &glyphs[0],
- &advances[0],
- origin2);
- if (!success && executions == 0) {
- // Ask the browser to load the font for us and retry.
- webkit_glue::EnsureFontLoaded(font->platformData().hfont());
- continue;
+ int glyphIndex = 0;
+ int chunkX = 0; // x offset of this span from the point
+ while (glyphIndex < numGlyphs) {
+ // how many chars will be in this chunk?
+ int curLen = std::min(kMaxBufferLength, numGlyphs - glyphIndex);
+
+ glyphs.resize(curLen);
+ advances.resize(curLen);
+
+ int curWidth = 0;
+ for (int i = 0; i < curLen; ++i, ++glyphIndex) {
+ glyphs[i] = glyphBuffer.glyphAt(from + glyphIndex);
+ advances[i] =
+ static_cast<int>(glyphBuffer.advanceAt(from + glyphIndex));
+ curWidth += advances[i];
+ }
+
+ SkPoint origin2 = point;
+ origin2.fX += chunkX;
+
+ bool success = false;
+ for (int executions = 0; executions < 2; ++executions) {
+ // The 'origin' represents the baseline, so we need to move it up
+ // to the top of the bounding square by subtracting the ascent
+ success = !!ExtTextOut(hdc, static_cast<int>(origin2.fX),
+ static_cast<int>(origin2.fY) - ascent(),
+ ETO_GLYPH_INDEX, NULL,
+ reinterpret_cast<const wchar_t*>(&glyphs[0]),
+ curLen,
+ &advances[0]);
+
+ if (!success && executions == 0) {
+ // Ask the browser to load the font for us and retry.
+ webkit_glue::EnsureFontLoaded(font->platformData().hfont());
+ continue;
+ }
+ break;
}
- break;
- }
- ASSERT(success);
+ ASSERT(success);
- chunk_x += cur_width;
+ chunkX += curWidth;
}
+
+ SelectObject(hdc, oldFont);
+ context->canvas()->endPlatformPaint();
}
FloatRect Font::selectionRectForComplexText(const TextRun& run,
@@ -126,14 +149,39 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run,
left - right, static_cast<float>(h));
}
-void Font::drawComplexText(GraphicsContext* context,
+void Font::drawComplexText(GraphicsContext* graphicsContext,
const TextRun& run,
const FloatPoint& point,
int from,
int to) const
{
+ PlatformGraphicsContext* context = graphicsContext->platformContext();
UniscribeStateTextRun state(run, *this);
- context->platformContext()->paintComplexText(state, point, from, to, ascent());
+
+ SkColor color = context->fillColor();
+ uint8 alpha = SkColorGetA(color);
+ // Skip 100% transparent text; no need to draw anything.
+ if (!alpha)
+ return;
+
+ HDC hdc = context->canvas()->beginPlatformPaint();
+
+ // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
+ // Enforce non-transparent color.
+ color = SkColorSetRGB(SkColorGetR(color),
+ SkColorGetG(color),
+ SkColorGetB(color));
+ SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
+ SetBkMode(hdc, TRANSPARENT);
+
+ // Uniscribe counts the coordinates from the upper left, while WebKit uses
+ // the baseline, so we have to subtract off the ascent.
+ state.Draw(hdc,
+ static_cast<int>(point.x()),
+ static_cast<int>(point.y() - ascent()),
+ from,
+ to);
+ context->canvas()->endPlatformPaint();
}
float Font::floatWidthForComplexText(const TextRun& run) const
diff --git a/webkit/port/platform/graphics/IconWin.cpp b/webkit/port/platform/graphics/IconWin.cpp
index 1856add..b1a8d70 100644
--- a/webkit/port/platform/graphics/IconWin.cpp
+++ b/webkit/port/platform/graphics/IconWin.cpp
@@ -54,12 +54,15 @@ PassRefPtr<Icon> Icon::newIconForFile(const String& filename)
return adoptRef(new Icon(sfi.hIcon));
}
-void Icon::paint(GraphicsContext* context, const IntRect& r)
+void Icon::paint(GraphicsContext* context, const IntRect& rect)
{
if (context->paintingDisabled())
return;
- context->platformContext()->paintIcon(m_icon, r);
+ HDC hdc = context->platformContext()->canvas()->beginPlatformPaint();
+ DrawIconEx(hdc, rect.x(), rect.y(), m_icon, rect.width(), rect.height(),
+ 0, 0, DI_NORMAL);
+ context->platformContext()->canvas()->endPlatformPaint();
}
} // namespace WebCore
diff --git a/webkit/port/platform/graphics/ImageSkia.cpp b/webkit/port/platform/graphics/ImageSkia.cpp
index 5cf364d..5ffd3e3 100644
--- a/webkit/port/platform/graphics/ImageSkia.cpp
+++ b/webkit/port/platform/graphics/ImageSkia.cpp
@@ -60,6 +60,218 @@ namespace WebCore {
namespace {
+// Used by computeResamplingMode to tell how bitmaps should be resampled.
+enum ResamplingMode {
+ // Nearest neighbor resampling. Used when we detect that the page is
+ // trying to make a pattern by stretching a small bitmap very large.
+ RESAMPLE_NONE,
+
+ // Default skia resampling. Used for large growing of images where high
+ // quality resampling doesn't get us very much except a slowdown.
+ RESAMPLE_LINEAR,
+
+ // High quality resampling.
+ RESAMPLE_AWESOME,
+};
+
+// static
+ResamplingMode computeResamplingMode(const NativeImageSkia& bitmap,
+ int srcWidth, int srcHeight,
+ float destWidth, float destHeight)
+{
+ int destIWidth = static_cast<int>(destWidth);
+ int destIHeight = static_cast<int>(destHeight);
+
+ // The percent change below which we will not resample. This usually means
+ // an off-by-one error on the web page, and just doing nearest neighbor
+ // sampling is usually good enough.
+ const float kFractionalChangeThreshold = 0.025f;
+
+ // Images smaller than this in either direction are considered "small" and
+ // are not resampled ever (see below).
+ const int kSmallImageSizeThreshold = 8;
+
+ // The amount an image can be stretched in a single direction before we
+ // say that it is being stretched so much that it must be a line or
+ // background that doesn't need resampling.
+ const float kLargeStretch = 3.0f;
+
+ // Figure out if we should resample this image. We try to prune out some
+ // common cases where resampling won't give us anything, since it is much
+ // slower than drawing stretched.
+ if (srcWidth == destIWidth && srcHeight == destIHeight) {
+ // We don't need to resample if the source and destination are the same.
+ return RESAMPLE_NONE;
+ }
+
+ if (srcWidth <= kSmallImageSizeThreshold ||
+ srcHeight <= kSmallImageSizeThreshold ||
+ destWidth <= kSmallImageSizeThreshold ||
+ destHeight <= kSmallImageSizeThreshold) {
+ // Never resample small images. These are often used for borders and
+ // rules (think 1x1 images used to make lines).
+ return RESAMPLE_NONE;
+ }
+
+ if (srcHeight * kLargeStretch <= destHeight ||
+ srcWidth * kLargeStretch <= destWidth) {
+ // Large image detected.
+
+ // Don't resample if it is being stretched a lot in only one direction.
+ // This is trying to catch cases where somebody has created a border
+ // (which might be large) and then is stretching it to fill some part
+ // of the page.
+ if (srcWidth == destWidth || srcHeight == destHeight)
+ return RESAMPLE_NONE;
+
+ // The image is growing a lot and in more than one direction. Resampling
+ // is slow and doesn't give us very much when growing a lot.
+ return RESAMPLE_LINEAR;
+ }
+
+ if ((fabs(destWidth - srcWidth) / srcWidth <
+ kFractionalChangeThreshold) &&
+ (fabs(destHeight - srcHeight) / srcHeight <
+ kFractionalChangeThreshold)) {
+ // It is disappointingly common on the web for image sizes to be off by
+ // one or two pixels. We don't bother resampling if the size difference
+ // is a small fraction of the original size.
+ return RESAMPLE_NONE;
+ }
+
+ // When the image is not yet done loading, use linear. We don't cache the
+ // partially resampled images, and as they come in incrementally, it causes
+ // us to have to resample the whole thing every time.
+ if (!bitmap.isDataComplete())
+ return RESAMPLE_LINEAR;
+
+ // Everything else gets resampled.
+ return RESAMPLE_AWESOME;
+}
+
+// Draws the given bitmap to the given canvas. The subset of the source bitmap
+// identified by src_rect is drawn to the given destination rect. The bitmap
+// will be resampled to resample_width * resample_height (this is the size of
+// the whole image, not the subset). See shouldResampleBitmap for more.
+//
+// This does a lot of computation to resample only the portion of the bitmap
+// that will only be drawn. This is critical for performance since when we are
+// scrolling, for example, we are only drawing a small strip of the image.
+// Resampling the whole image every time is very slow, so this speeds up things
+// dramatically.
+void drawResampledBitmap(SkCanvas& canvas,
+ SkPaint& paint,
+ const NativeImageSkia& bitmap,
+ const SkIRect& srcIRect,
+ const SkRect& destRect)
+{
+ // First get the subset we need. This is efficient and does not copy pixels.
+ SkBitmap subset;
+ bitmap.extractSubset(&subset, srcIRect);
+ SkRect srcRect;
+ srcRect.set(srcIRect);
+
+ // Whether we're doing a subset or using the full source image.
+ bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0 &&
+ srcIRect.width() == bitmap.width() &&
+ srcIRect.height() == bitmap.height();
+
+ // We will always draw in integer sizes, so round the destination rect.
+ SkIRect destRectRounded;
+ destRect.round(&destRectRounded);
+ SkIRect resizedImageRect; // Represents the size of the resized image.
+ resizedImageRect.set(0, 0,
+ destRectRounded.width(), destRectRounded.height());
+
+ if (srcIsFull &&
+ bitmap.hasResizedBitmap(destRectRounded.width(),
+ destRectRounded.height())) {
+ // Yay, this bitmap frame already has a resized version.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
+ destRectRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ return;
+ }
+
+ // Compute the visible portion of our rect.
+ SkRect destBitmapSubsetSk;
+ ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
+ destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
+
+ // The matrix inverting, etc. could have introduced rounding error which
+ // causes the bounds to be outside of the resized bitmap. We round outward
+ // so we always lean toward it being larger rather than smaller than we
+ // need, and then clamp to the bitmap bounds so we don't get any invalid
+ // data.
+ SkIRect destBitmapSubsetSkI;
+ destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
+ if (!destBitmapSubsetSkI.intersect(resizedImageRect))
+ return; // Resized image does not intersect.
+
+ if (srcIsFull && bitmap.shouldCacheResampling(
+ resizedImageRect.width(),
+ resizedImageRect.height(),
+ destBitmapSubsetSkI.width(),
+ destBitmapSubsetSkI.height())) {
+ // We're supposed to resize the entire image and cache it, even though
+ // we don't need all of it.
+ SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
+ destRectRounded.height());
+ canvas.drawBitmapRect(resampled, 0, destRect, &paint);
+ } else {
+ // We should only resize the exposed part of the bitmap to do the
+ // minimal possible work.
+ gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft,
+ destBitmapSubsetSkI.fTop,
+ destBitmapSubsetSkI.width(),
+ destBitmapSubsetSkI.height());
+
+ // Resample the needed part of the image.
+ SkBitmap resampled = gfx::ImageOperations::Resize(subset,
+ gfx::ImageOperations::RESIZE_LANCZOS3,
+ gfx::Size(destRectRounded.width(), destRectRounded.height()),
+ destBitmapSubset);
+
+ // Compute where the new bitmap should be drawn. Since our new bitmap
+ // may be smaller than the original, we have to shift it over by the
+ // same amount that we cut off the top and left.
+ SkRect offsetDestRect = {
+ destBitmapSubset.x() + destRect.fLeft,
+ destBitmapSubset.y() + destRect.fTop,
+ destBitmapSubset.right() + destRect.fLeft,
+ destBitmapSubset.bottom() + destRect.fTop };
+
+ canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
+ }
+}
+
+void paintSkBitmap(PlatformContextSkia* platformContext,
+ const NativeImageSkia& bitmap,
+ const SkIRect& srcRect,
+ const SkRect& destRect,
+ const SkPorterDuff::Mode& compOp)
+{
+ SkPaint paint;
+ paint.setPorterDuffXfermode(compOp);
+
+ gfx::PlatformCanvas* canvas = platformContext->canvas();
+
+ ResamplingMode resampling = platformContext->IsPrinting() ? RESAMPLE_NONE :
+ computeResamplingMode(bitmap, srcRect.width(), srcRect.height(),
+ SkScalarToFloat(destRect.width()),
+ SkScalarToFloat(destRect.height()));
+ if (resampling == RESAMPLE_AWESOME) {
+ paint.setFilterBitmap(false);
+ drawResampledBitmap(*canvas, paint, bitmap, srcRect, destRect);
+ } else {
+ // No resampling necessary, we can just draw the bitmap.
+ // Note: for serialization, we will want to subset the bitmap first so
+ // we don't send extra pixels.
+ paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
+ canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
+ }
+}
+
// Transforms the given dimensions with the given matrix. Used to see how big
// images will be once transformed.
void TransformDimensions(const SkMatrix& matrix,
@@ -185,20 +397,19 @@ void Image::drawPattern(GraphicsContext* context,
&dest_bitmap_width, &dest_bitmap_height);
// Compute the resampling mode.
- PlatformContextSkia::ResamplingMode resampling;
+ ResamplingMode resampling;
if (context->platformContext()->IsPrinting())
- resampling = PlatformContextSkia::RESAMPLE_LINEAR;
+ resampling = RESAMPLE_LINEAR;
else {
- resampling = PlatformContextSkia::computeResamplingMode(
- *bitmap,
- srcRect.width(), srcRect.height(),
- dest_bitmap_width, dest_bitmap_height);
+ resampling = computeResamplingMode(*bitmap,
+ srcRect.width(), srcRect.height(),
+ dest_bitmap_width, dest_bitmap_height);
}
// Load the transform WebKit requested.
SkMatrix matrix(patternTransform);
- if (resampling == PlatformContextSkia::RESAMPLE_AWESOME) {
+ if (resampling == RESAMPLE_AWESOME) {
// Do nice resampling.
SkBitmap resampled = gfx::ImageOperations::Resize(src_subset,
gfx::ImageOperations::RESIZE_LANCZOS3,
@@ -228,7 +439,7 @@ void Image::drawPattern(GraphicsContext* context,
SkPaint paint;
paint.setShader(shader)->unref();
paint.setPorterDuffXfermode(WebCoreCompositeToSkiaComposite(compositeOp));
- paint.setFilterBitmap(resampling == PlatformContextSkia::RESAMPLE_LINEAR);
+ paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
context->platformContext()->paintSkPaint(destRect, paint);
}
@@ -267,8 +478,11 @@ void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
if (srcRect.isEmpty() || dstRect.isEmpty())
return; // Nothing to draw.
- ctxt->platformContext()->paintSkBitmap(*bm, enclosingIntRect(srcRect),
- enclosingIntRect(dstRect), WebCoreCompositeToSkiaComposite(compositeOp));
+ paintSkBitmap(ctxt->platformContext(),
+ *bm,
+ enclosingIntRect(srcRect),
+ enclosingIntRect(dstRect),
+ WebCoreCompositeToSkiaComposite(compositeOp));
startAnimation();
}
@@ -281,11 +495,11 @@ void BitmapImageSingleFrameSkia::draw(GraphicsContext* ctxt,
if (srcRect.isEmpty() || dstRect.isEmpty())
return; // Nothing to draw.
- ctxt->platformContext()->paintSkBitmap(
- m_nativeImage,
- enclosingIntRect(srcRect),
- enclosingIntRect(dstRect),
- WebCoreCompositeToSkiaComposite(compositeOp));
+ paintSkBitmap(ctxt->platformContext(),
+ m_nativeImage,
+ enclosingIntRect(srcRect),
+ enclosingIntRect(dstRect),
+ WebCoreCompositeToSkiaComposite(compositeOp));
}
PassRefPtr<BitmapImageSingleFrameSkia> BitmapImageSingleFrameSkia::create(
diff --git a/webkit/port/platform/graphics/PlatformContextSkia.cpp b/webkit/port/platform/graphics/PlatformContextSkia.cpp
index 3c6b53e..16dbce8 100644
--- a/webkit/port/platform/graphics/PlatformContextSkia.cpp
+++ b/webkit/port/platform/graphics/PlatformContextSkia.cpp
@@ -43,113 +43,6 @@
#include "SkShader.h"
#include "SkDashPathEffect.h"
-#if PLATFORM(WIN_OS)
-#include <vssym32.h>
-#include "base/gfx/native_theme.h"
-#include "ThemeData.h"
-#include "UniscribeStateTextRun.h"
-#endif
-
-namespace {
-
-// Draws the given bitmap to the given canvas. The subset of the source bitmap
-// identified by src_rect is drawn to the given destination rect. The bitmap
-// will be resampled to resample_width * resample_height (this is the size of
-// the whole image, not the subset). See shouldResampleBitmap for more.
-//
-// This does a lot of computation to resample only the portion of the bitmap
-// that will only be drawn. This is critical for performance since when we are
-// scrolling, for example, we are only drawing a small strip of the image.
-// Resampling the whole image every time is very slow, so this speeds up things
-// dramatically.
-void DrawResampledBitmap(SkCanvas& canvas,
- SkPaint& paint,
- const NativeImageSkia& bitmap,
- const SkIRect& srcIRect,
- const SkRect& destRect)
-{
- // First get the subset we need. This is efficient and does not copy pixels.
- SkBitmap subset;
- bitmap.extractSubset(&subset, srcIRect);
- SkRect srcRect;
- srcRect.set(srcIRect);
-
- // Whether we're doing a subset or using the full source image.
- bool srcIsFull = srcIRect.fLeft == 0 && srcIRect.fTop == 0 &&
- srcIRect.width() == bitmap.width() &&
- srcIRect.height() == bitmap.height();
-
- // We will always draw in integer sizes, so round the destination rect.
- SkIRect destRectRounded;
- destRect.round(&destRectRounded);
- SkIRect resizedImageRect; // Represents the size of the resized image.
- resizedImageRect.set(0, 0,
- destRectRounded.width(), destRectRounded.height());
-
- if (srcIsFull &&
- bitmap.hasResizedBitmap(destRectRounded.width(),
- destRectRounded.height())) {
- // Yay, this bitmap frame already has a resized version.
- SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
- destRectRounded.height());
- canvas.drawBitmapRect(resampled, 0, destRect, &paint);
- return;
- }
-
- // Compute the visible portion of our rect.
- SkRect destBitmapSubsetSk;
- ClipRectToCanvas(canvas, destRect, &destBitmapSubsetSk);
- destBitmapSubsetSk.offset(-destRect.fLeft, -destRect.fTop);
-
- // The matrix inverting, etc. could have introduced rounding error which
- // causes the bounds to be outside of the resized bitmap. We round outward
- // so we always lean toward it being larger rather than smaller than we
- // need, and then clamp to the bitmap bounds so we don't get any invalid
- // data.
- SkIRect destBitmapSubsetSkI;
- destBitmapSubsetSk.roundOut(&destBitmapSubsetSkI);
- if (!destBitmapSubsetSkI.intersect(resizedImageRect))
- return; // Resized image does not intersect.
-
- if (srcIsFull && bitmap.shouldCacheResampling(
- resizedImageRect.width(),
- resizedImageRect.height(),
- destBitmapSubsetSkI.width(),
- destBitmapSubsetSkI.height())) {
- // We're supposed to resize the entire image and cache it, even though
- // we don't need all of it.
- SkBitmap resampled = bitmap.resizedBitmap(destRectRounded.width(),
- destRectRounded.height());
- canvas.drawBitmapRect(resampled, 0, destRect, &paint);
- } else {
- // We should only resize the exposed part of the bitmap to do the
- // minimal possible work.
- gfx::Rect destBitmapSubset(destBitmapSubsetSkI.fLeft,
- destBitmapSubsetSkI.fTop,
- destBitmapSubsetSkI.width(),
- destBitmapSubsetSkI.height());
-
- // Resample the needed part of the image.
- SkBitmap resampled = gfx::ImageOperations::Resize(subset,
- gfx::ImageOperations::RESIZE_LANCZOS3,
- gfx::Size(destRectRounded.width(), destRectRounded.height()),
- destBitmapSubset);
-
- // Compute where the new bitmap should be drawn. Since our new bitmap
- // may be smaller than the original, we have to shift it over by the
- // same amount that we cut off the top and left.
- SkRect offsetDestRect = {
- destBitmapSubset.x() + destRect.fLeft,
- destBitmapSubset.y() + destRect.fTop,
- destBitmapSubset.right() + destRect.fLeft,
- destBitmapSubset.bottom() + destRect.fTop };
-
- canvas.drawBitmapRect(resampled, 0, offsetDestRect, &paint);
- }
-}
-
-} // namespace
-
// State -----------------------------------------------------------------------
// Encapsulates the additional painting state information we store for each
@@ -215,9 +108,9 @@ PlatformContextSkia::State::State()
PlatformContextSkia::State::State(const State& other)
{
- other.m_looper->safeRef();
memcpy(this, &other, sizeof(State));
+ m_looper->safeRef();
m_dash->safeRef();
m_gradient->safeRef();
m_pattern->safeRef();
@@ -249,26 +142,18 @@ PlatformContextSkia::PlatformContextSkia(gfx::PlatformCanvas* canvas)
: m_canvas(canvas)
, m_stateStack(sizeof(State))
{
- State* state = reinterpret_cast<State*>(m_stateStack.push_back());
- new (state) State();
- m_state = state;
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
}
PlatformContextSkia::~PlatformContextSkia()
{
- // We force restores so we don't leak any subobjects owned by our
- // stack of State records.
- while (m_stateStack.count() > 0) {
- reinterpret_cast<State*>(m_stateStack.back())->~State();
- m_stateStack.pop_back();
- }
}
void PlatformContextSkia::save()
{
- State* newState = reinterpret_cast<State*>(m_stateStack.push_back());
- new (newState) State(*m_state);
- m_state = newState;
+ m_stateStack.append(State());
+ m_state = &m_stateStack.last();
// Save our native canvas.
canvas()->save();
@@ -276,13 +161,11 @@ void PlatformContextSkia::save()
void PlatformContextSkia::restore()
{
+ m_stateStack.removeLast();
+ m_state = &m_stateStack.last();
+
// Restore our native canvas.
canvas()->restore();
-
- m_state->~State();
- m_stateStack.pop_back();
-
- m_state = reinterpret_cast<State*>(m_stateStack.back());
}
void PlatformContextSkia::drawRect(SkRect rect)
@@ -505,249 +388,12 @@ void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
}
}
-// TODO(brettw) all this platform stuff should be moved out of this class into
-// platform-specific files for that type of thing (e.g. to FontWin).
-#if PLATFORM(WIN_OS)
-
-const gfx::NativeTheme* PlatformContextSkia::nativeTheme()
-{
- return gfx::NativeTheme::instance();
-}
-
-// TODO(brettw) move to a platform-specific file.
-void PlatformContextSkia::paintIcon(HICON icon, const SkIRect& rect)
-{
- HDC hdc = m_canvas->beginPlatformPaint();
- DrawIconEx(hdc, rect.fLeft, rect.fTop, icon, rect.width(), rect.height(),
- 0, 0, DI_NORMAL);
- m_canvas->endPlatformPaint();
-}
-
-// RenderThemeWin.cpp
-void PlatformContextSkia::paintButton(const SkIRect& widgetRect,
- const ThemeData& themeData)
-{
- RECT rect(gfx::SkIRectToRECT(widgetRect));
- HDC hdc = m_canvas->beginPlatformPaint();
- int state = themeData.m_state;
- nativeTheme()->PaintButton(hdc,
- themeData.m_part,
- state,
- themeData.m_classicState,
- &rect);
- m_canvas->endPlatformPaint();
-}
-
-void PlatformContextSkia::paintTextField(const SkIRect& widgetRect,
- const ThemeData& themeData,
- SkColor c,
- bool drawEdges)
-{
- RECT rect(gfx::SkIRectToRECT(widgetRect));
- HDC hdc = m_canvas->beginPlatformPaint();
- nativeTheme()->PaintTextField(hdc,
- themeData.m_part,
- themeData.m_state,
- themeData.m_classicState,
- &rect,
- gfx::SkColorToCOLORREF(c),
- true,
- drawEdges);
- m_canvas->endPlatformPaint();
-}
-
-void PlatformContextSkia::paintMenuListArrowButton(const SkIRect& widgetRect,
- unsigned state,
- unsigned classicState)
-{
- RECT rect(gfx::SkIRectToRECT(widgetRect));
- HDC hdc = m_canvas->beginPlatformPaint();
- nativeTheme()->PaintMenuList(hdc,
- CP_DROPDOWNBUTTON,
- state,
- classicState,
- &rect);
- m_canvas->endPlatformPaint();
-}
-
-void PlatformContextSkia::paintComplexText(UniscribeStateTextRun& state,
- const SkPoint& point,
- int from,
- int to,
- int ascent)
-{
- SkColor color(fillColor());
- uint8 alpha = SkColorGetA(color);
- // Skip 100% transparent text; no need to draw anything.
- if (!alpha)
- return;
-
- HDC hdc = m_canvas->beginPlatformPaint();
-
- // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
- // Enforce non-transparent color.
- color = SkColorSetRGB(SkColorGetR(color),
- SkColorGetG(color),
- SkColorGetB(color));
- SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
- SetBkMode(hdc, TRANSPARENT);
-
- // Uniscribe counts the coordinates from the upper left, while WebKit uses
- // the baseline, so we have to subtract off the ascent.
- state.Draw(hdc,
- static_cast<int>(point.fX),
- static_cast<int>(point.fY - ascent),
- from,
- to);
- m_canvas->endPlatformPaint();
-}
-
-// TODO(brettw) move to FontWin
-bool PlatformContextSkia::paintText(FontHandle hfont,
- int numberGlyph,
- const uint16* glyphs,
- const int* advances,
- const SkPoint& origin)
-{
- SkColor color(fillColor());
- uint8 alpha = SkColorGetA(color);
- // Skip 100% transparent text; no need to draw anything.
- if (!alpha)
- return true;
-
- bool success = false;
- HDC hdc = m_canvas->beginPlatformPaint();
- HGDIOBJ oldFont = SelectObject(hdc, hfont);
-
- // TODO(maruel): http://b/700464 SetTextColor doesn't support transparency.
- // Enforce non-transparent color.
- color = SkColorSetRGB(SkColorGetR(color),
- SkColorGetG(color),
- SkColorGetB(color));
- SetTextColor(hdc, gfx::SkColorToCOLORREF(color));
- SetBkMode(hdc, TRANSPARENT);
-
- // The 'origin' represents the baseline, so we need to move it up to the
- // top of the bounding square by subtracting the ascent
- success = !!ExtTextOut(hdc, static_cast<int>(origin.fX),
- static_cast<int>(origin.fY),
- ETO_GLYPH_INDEX, 0,
- reinterpret_cast<const wchar_t*>(glyphs),
- numberGlyph,
- advances);
- SelectObject(hdc, oldFont);
- m_canvas->endPlatformPaint();
- return success;
-}
-
-#endif // PLATFORM(WIN_OS);
-
void PlatformContextSkia::paintSkPaint(const SkRect& rect,
const SkPaint& paint)
{
m_canvas->drawRect(rect, paint);
}
-// static
-PlatformContextSkia::ResamplingMode PlatformContextSkia::computeResamplingMode(
- const NativeImageSkia& bitmap,
- int srcWidth, int srcHeight,
- float destWidth, float destHeight)
-{
- int destIWidth = static_cast<int>(destWidth);
- int destIHeight = static_cast<int>(destHeight);
-
- // The percent change below which we will not resample. This usually means
- // an off-by-one error on the web page, and just doing nearest neighbor
- // sampling is usually good enough.
- const float kFractionalChangeThreshold = 0.025f;
-
- // Images smaller than this in either direction are considered "small" and
- // are not resampled ever (see below).
- const int kSmallImageSizeThreshold = 8;
-
- // The amount an image can be stretched in a single direction before we
- // say that it is being stretched so much that it must be a line or
- // background that doesn't need resampling.
- const float kLargeStretch = 3.0f;
-
- // Figure out if we should resample this image. We try to prune out some
- // common cases where resampling won't give us anything, since it is much
- // slower than drawing stretched.
- if (srcWidth == destIWidth && srcHeight == destIHeight) {
- // We don't need to resample if the source and destination are the same.
- return RESAMPLE_NONE;
- }
-
- if (srcWidth <= kSmallImageSizeThreshold ||
- srcHeight <= kSmallImageSizeThreshold ||
- destWidth <= kSmallImageSizeThreshold ||
- destHeight <= kSmallImageSizeThreshold) {
- // Never resample small images. These are often used for borders and
- // rules (think 1x1 images used to make lines).
- return RESAMPLE_NONE;
- }
-
- if (srcHeight * kLargeStretch <= destHeight ||
- srcWidth * kLargeStretch <= destWidth) {
- // Large image detected.
-
- // Don't resample if it is being stretched a lot in only one direction.
- // This is trying to catch cases where somebody has created a border
- // (which might be large) and then is stretching it to fill some part
- // of the page.
- if (srcWidth == destWidth || srcHeight == destHeight)
- return RESAMPLE_NONE;
-
- // The image is growing a lot and in more than one direction. Resampling
- // is slow and doesn't give us very much when growing a lot.
- return RESAMPLE_LINEAR;
- }
-
- if ((fabs(destWidth - srcWidth) / srcWidth <
- kFractionalChangeThreshold) &&
- (fabs(destHeight - srcHeight) / srcHeight <
- kFractionalChangeThreshold)) {
- // It is disappointingly common on the web for image sizes to be off by
- // one or two pixels. We don't bother resampling if the size difference
- // is a small fraction of the original size.
- return RESAMPLE_NONE;
- }
-
- // When the image is not yet done loading, use linear. We don't cache the
- // partially resampled images, and as they come in incrementally, it causes
- // us to have to resample the whole thing every time.
- if (!bitmap.isDataComplete())
- return RESAMPLE_LINEAR;
-
- // Everything else gets resampled.
- return RESAMPLE_AWESOME;
-}
-
-void PlatformContextSkia::paintSkBitmap(const NativeImageSkia& bitmap,
- const SkIRect& srcRect,
- const SkRect& destRect,
- const SkPorterDuff::Mode& compOp)
-{
- SkPaint paint;
- paint.setPorterDuffXfermode(compOp);
-
- ResamplingMode resampling = IsPrinting() ? RESAMPLE_NONE :
- computeResamplingMode(bitmap, srcRect.width(), srcRect.height(),
- SkScalarToFloat(destRect.width()),
- SkScalarToFloat(destRect.height()));
- if (resampling == RESAMPLE_AWESOME) {
- paint.setFilterBitmap(false);
- DrawResampledBitmap(*m_canvas, paint, bitmap, srcRect, destRect);
- } else {
- // No resampling necessary, we can just draw the bitmap.
- // Note: for serialization, we will want to subset the bitmap first so
- // we don't send extra pixels.
- paint.setFilterBitmap(resampling == RESAMPLE_LINEAR);
- m_canvas->drawBitmapRect(bitmap, &srcRect, destRect, &paint);
- }
-}
-
const SkBitmap* PlatformContextSkia::bitmap() const
{
return &m_canvas->getDevice()->accessBitmap(false);
diff --git a/webkit/port/platform/graphics/PlatformContextSkia.h b/webkit/port/platform/graphics/PlatformContextSkia.h
index ab407bb..ecc56020 100644
--- a/webkit/port/platform/graphics/PlatformContextSkia.h
+++ b/webkit/port/platform/graphics/PlatformContextSkia.h
@@ -38,27 +38,7 @@
#include "SkPath.h"
#include "GraphicsContext.h"
-#include "ThemeData.h"
-
-#if defined(OS_WIN)
-typedef HICON IconHandle;
-typedef HFONT FontHandle;
-#elif defined(OS_MACOSX)
-typedef CGImageRef IconHandle;
-typedef CTFontRef FontHandle;
-#elif defined(OS_LINUX)
-// TODO(erg): Type needs to be defined for half the rest of the stack to
-// compile. When the corresponding implementation to this file gets written,
-// these void pointers need to be replaced with whatever we end up using.
-typedef void* IconHandle;
-typedef void* FontHandle;
-#endif
-
-class UniscribeStateTextRun;
-
-namespace gfx {
-class NativeTheme;
-}
+#include "wtf/Vector.h"
// This class holds the platform-specific state for GraphicsContext. We put
// most of our Skia wrappers on this class. In theory, a lot of this stuff could
@@ -79,20 +59,6 @@ class NativeTheme;
// state to be pushed and popped along with the bitmap.
class PlatformContextSkia {
public:
- // Used by computeResamplingMode to tell how bitmaps should be resampled.
- enum ResamplingMode {
- // Nearest neighbor resampling. Used when we detect that the page is
- // trying to make a pattern by stretching a small bitmap very large.
- RESAMPLE_NONE,
-
- // Default skia resampling. Used for large growing of images where high
- // quality resampling doesn't get us very much except a slowdown.
- RESAMPLE_LINEAR,
-
- // High quality resampling.
- RESAMPLE_AWESOME,
- };
-
// For printing, there shouldn't be any canvas. canvas can be NULL.
PlatformContextSkia(gfx::PlatformCanvas* canvas);
~PlatformContextSkia();
@@ -150,60 +116,9 @@ public:
// TODO(brettw) why is this in this class?
void drawRect(SkRect rect);
- // Gets the default theme.
- static const gfx::NativeTheme* nativeTheme();
-
- void paintIcon(IconHandle icon, const SkIRect& rect);
- // TODO(brettw) these functions should not have to take GraphicsContext
- // pointers! This is cureently required because our theme drawing code
- // requires GraphicsContexts, but this class doesn't know about it. This
- // class's purpose seems no longer necessary, so everything can be moved to
- // GraphicsContext or ThemeWin, and these parameters can be removed.
- void paintButton(const SkIRect& widgetRect,
- const ThemeData& themeData);
- void paintTextField(const SkIRect& widgetRect,
- const ThemeData& themeData,
- SkColor c,
- bool drawEdges);
- void paintMenuListArrowButton(const SkIRect& widgetRect,
- unsigned state,
- unsigned classicState);
- void paintComplexText(UniscribeStateTextRun& state,
- const SkPoint& point,
- int from,
- int to,
- int ascent);
-
- // Draws the given glyphs at the given |origin|. |origin| is on the baseline
- // of the text, and the |ascender_height| must be given for some code paths
- // since Windows draws text from the upper left.
- bool paintText(FontHandle hfont,
- int number_glyph,
- const uint16* glyphs,
- const int* advances,
- const SkPoint& origin);
-
// TODO(maruel): I'm still unsure how I will serialize this call.
void paintSkPaint(const SkRect& rect, const SkPaint& paint);
- // Draws the given bitmap in the canvas at the location specified in
- // |dest_rect|. It will be resampled as necessary to fill that rectangle.
- // The |src_rect| indicates the subset of the bitmap to draw.
- void paintSkBitmap(const NativeImageSkia& bitmap,
- const SkIRect& srcRect,
- const SkRect& destRect,
- const SkPorterDuff::Mode& compositeOp);
-
- // Returns true if the given bitmap subset should be resampled before being
- // painted into a rectangle of the given size. This is used to indicate
- // whether bitmap painting should be optimized by not resampling, or given
- // higher quality by resampling.
- static ResamplingMode computeResamplingMode(const NativeImageSkia& bitmap,
- int srcWidth,
- int srcHeight,
- float destWidth,
- float destHeight);
-
const SkBitmap* bitmap() const;
// Returns the canvas used for painting, NOT guaranteed to be non-NULL.
@@ -227,7 +142,7 @@ private:
// States stack. Enables local drawing state change with save()/restore()
// calls.
- SkDeque m_stateStack;
+ WTF::Vector<State> m_stateStack;
// Pointer to the current drawing state. This is a cached value of
// mStateStack.back().
State* m_state;
diff --git a/webkit/port/rendering/RenderThemeWin.cpp b/webkit/port/rendering/RenderThemeWin.cpp
index aeac95d..2bb81ab 100644
--- a/webkit/port/rendering/RenderThemeWin.cpp
+++ b/webkit/port/rendering/RenderThemeWin.cpp
@@ -36,6 +36,7 @@
#include "base/gfx/native_theme.h"
#include "base/gfx/font_utils.h"
+#include "base/gfx/skia_utils.h"
#include "base/win_util.h"
#include "webkit/glue/webkit_glue.h"
@@ -475,10 +476,26 @@ ThemeData RenderThemeWin::getThemeData(RenderObject* o)
return result;
}
-bool RenderThemeWin::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r)
+bool RenderThemeWin::paintButton(RenderObject* o,
+ const RenderObject::PaintInfo& i,
+ const IntRect& r)
{
- // Get the correct theme data for a button and paint the button.
- i.context->platformContext()->paintButton(r, getThemeData(o));
+ const ThemeData& themeData = getThemeData(o);
+
+ RECT rect;
+ rect.left = r.x();
+ rect.top = r.y();
+ rect.right = r.right();
+ rect.bottom = r.bottom();
+
+ HDC hdc = i.context->platformContext()->canvas()->beginPlatformPaint();
+ int state = themeData.m_state;
+ gfx::NativeTheme::instance()->PaintButton(hdc,
+ themeData.m_part,
+ state,
+ themeData.m_classicState,
+ &rect);
+ i.context->platformContext()->canvas()->endPlatformPaint();
return false;
}
@@ -541,18 +558,39 @@ bool RenderThemeWin::paintTextField(RenderObject* o, const RenderObject::PaintIn
return paintTextFieldInternal(o, i, r, true);
}
-bool RenderThemeWin::paintTextFieldInternal(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r, bool drawEdges)
+bool RenderThemeWin::paintTextFieldInternal(RenderObject* o,
+ const RenderObject::PaintInfo& i,
+ const IntRect& r,
+ bool drawEdges)
{
- // Nasty hack to make us not paint the border on text fields with a border-radius.
- // Webkit paints elements with border-radius for us.
- // TODO(ojan): Get rid of this if-check once we can properly clip rounded borders
- // http://b/1112604 and http://b/1108635
- // TODO(ojan): make sure we do the right thing if css background-clip is set.
+ // Nasty hack to make us not paint the border on text fields with a
+ // border-radius. Webkit paints elements with border-radius for us.
+ // TODO(ojan): Get rid of this if-check once we can properly clip rounded
+ // borders: http://b/1112604 and http://b/1108635
+ // TODO(ojan): make sure we do the right thing if css background-clip is
+ // set.
if (o->style()->hasBorderRadius())
- return false;
-
- // Get the correct theme data for a textfield and paint the text field.
- i.context->platformContext()->paintTextField(r, getThemeData(o), o->style()->backgroundColor().rgb(), drawEdges);
+ return false;
+
+ const ThemeData& themeData = getThemeData(o);
+
+ RECT rect;
+ rect.left = r.x();
+ rect.top = r.y();
+ rect.right = r.right();
+ rect.bottom = r.bottom();
+
+ HDC hdc = i.context->platformContext()->canvas()->beginPlatformPaint();
+ COLORREF clr = gfx::SkColorToCOLORREF(o->style()->backgroundColor().rgb());
+ gfx::NativeTheme::instance()->PaintTextField(hdc,
+ themeData.m_part,
+ themeData.m_state,
+ themeData.m_classicState,
+ &rect,
+ clr,
+ true,
+ drawEdges);
+ i.context->platformContext()->canvas()->endPlatformPaint();
return false;
}
@@ -619,17 +657,26 @@ bool RenderThemeWin::paintMenuList(RenderObject* o, const RenderObject::PaintInf
int buttonX;
if (r.right() - r.x() < buttonWidth) {
- buttonX = r.x();
+ buttonX = r.x();
} else {
- buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft;
+ buttonX = o->style()->direction() == LTR ? r.right() - spacingRight - buttonWidth : r.x() + spacingLeft;
}
- IntRect buttonRect(buttonX,
- r.y() + spacingTop,
- std::min(buttonWidth, r.right() - r.x()),
- r.height() - (spacingTop + spacingBottom));
+
+ // Compute the Windows rectangle of the button.
+ RECT rect;
+ rect.left = buttonX;
+ rect.top = r.y() + spacingTop;
+ rect.right = rect.left + std::min(buttonWidth, r.right() - r.x());
+ rect.bottom = rect.top + r.height() - (spacingTop + spacingBottom);
// Get the correct theme data for a textfield and paint the menu.
- i.context->platformContext()->paintMenuListArrowButton(buttonRect, determineState(o), determineClassicState(o));
+ HDC hdc = i.context->platformContext()->canvas()->beginPlatformPaint();
+ gfx::NativeTheme::instance()->PaintMenuList(hdc,
+ CP_DROPDOWNBUTTON,
+ determineState(o),
+ determineClassicState(o),
+ &rect);
+ i.context->platformContext()->canvas()->endPlatformPaint();
return false;
}