PassOwnPtr<DragImage> DragImage::create(const KURL& url, const String& inLabel, const FontDescription& systemFont, float deviceScaleFactor) { const Font labelFont = deriveDragLabelFont(kDragLinkLabelFontSize, FontWeightBold, systemFont); const Font urlFont = deriveDragLabelFont(kDragLinkUrlFontSize, FontWeightNormal, systemFont); FontCachePurgePreventer fontCachePurgePreventer; bool drawURLString = true; bool clipURLString = false; bool clipLabelString = false; String urlString = url.string(); String label = inLabel.stripWhiteSpace(); if (label.isEmpty()) { drawURLString = false; label = urlString; } // First step is drawing the link drag image width. TextRun labelRun(label.impl()); TextRun urlRun(urlString.impl()); IntSize labelSize(labelFont.width(labelRun), labelFont.fontMetrics().ascent() + labelFont.fontMetrics().descent()); if (labelSize.width() > kMaxDragLabelStringWidth) { labelSize.setWidth(kMaxDragLabelStringWidth); clipLabelString = true; } IntSize urlStringSize; IntSize imageSize(labelSize.width() + kDragLabelBorderX * 2, labelSize.height() + kDragLabelBorderY * 2); if (drawURLString) { urlStringSize.setWidth(urlFont.width(urlRun)); urlStringSize.setHeight(urlFont.fontMetrics().ascent() + urlFont.fontMetrics().descent()); imageSize.setHeight(imageSize.height() + urlStringSize.height()); if (urlStringSize.width() > kMaxDragLabelStringWidth) { imageSize.setWidth(kMaxDragLabelWidth); clipURLString = true; } else imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + kDragLabelBorderX * 2); } // We now know how big the image needs to be, so we create and // fill the background IntSize scaledImageSize = imageSize; scaledImageSize.scale(deviceScaleFactor); OwnPtr<ImageBuffer> buffer(ImageBuffer::create(scaledImageSize)); if (!buffer) return nullptr; buffer->canvas()->scale(deviceScaleFactor, deviceScaleFactor); const float DragLabelRadius = 5; IntRect rect(IntPoint(), imageSize); SkPaint backgroundPaint; backgroundPaint.setColor(SkColorSetRGB(140, 140, 140)); SkRRect rrect; rrect.setRectXY(SkRect::MakeWH(imageSize.width(), imageSize.height()), DragLabelRadius, DragLabelRadius); buffer->canvas()->drawRRect(rrect, backgroundPaint); // Draw the text SkPaint textPaint; if (drawURLString) { if (clipURLString) urlString = StringTruncator::centerTruncate(urlString, imageSize.width() - (kDragLabelBorderX * 2.0f), urlFont); IntPoint textPos(kDragLabelBorderX, imageSize.height() - (kLabelBorderYOffset + urlFont.fontMetrics().descent())); TextRun textRun(urlString); urlFont.drawText(buffer->canvas(), TextRunPaintInfo(textRun), textPos, deviceScaleFactor, textPaint); } if (clipLabelString) label = StringTruncator::rightTruncate(label, imageSize.width() - (kDragLabelBorderX * 2.0f), labelFont); bool hasStrongDirectionality; TextRun textRun = textRunWithDirectionality(label, &hasStrongDirectionality); IntPoint textPos(kDragLabelBorderX, kDragLabelBorderY + labelFont.fontDescription().computedPixelSize()); if (hasStrongDirectionality && textRun.direction() == RTL) { float textWidth = labelFont.width(textRun); int availableWidth = imageSize.width() - kDragLabelBorderX * 2; textPos.setX(availableWidth - ceilf(textWidth)); } labelFont.drawBidiText(buffer->canvas(), TextRunPaintInfo(textRun), FloatPoint(textPos), Font::DoNotPaintIfFontNotReady, deviceScaleFactor, textPaint); RefPtr<Image> image = buffer->newImageSnapshot(); return DragImage::create(image.get(), DoNotRespectImageOrientation, deviceScaleFactor); }
void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, const IntRect& rect) { Node* node = o->node(); if (!node) return; HTMLInputElement* input = node->toInputElement(); if (!input) return; HTMLDataListElement* dataList = static_cast<HTMLDataListElement*>(input->list()); if (!dataList) return; double min = input->minimum(); double max = input->maximum(); ControlPart part = o->style()->appearance(); // We don't support ticks on alternate sliders like MediaVolumeSliders. if (part != SliderHorizontalPart && part != SliderVerticalPart) return; bool isHorizontal = part == SliderHorizontalPart; IntSize thumbSize; RenderObject* thumbRenderer = input->sliderThumbElement()->renderer(); if (thumbRenderer) { RenderStyle* thumbStyle = thumbRenderer->style(); int thumbWidth = thumbStyle->width().intValue(); int thumbHeight = thumbStyle->height().intValue(); thumbSize.setWidth(isHorizontal ? thumbWidth : thumbHeight); thumbSize.setHeight(isHorizontal ? thumbHeight : thumbWidth); } IntSize tickSize = sliderTickSize(); float zoomFactor = o->style()->effectiveZoom(); FloatRect tickRect; int tickRegionSideMargin = 0; int tickRegionWidth = 0; IntRect trackBounds; RenderObject* trackRenderer = input->sliderTrackElement()->renderer(); // We can ignoring transforms because transform is handled by the graphics context. if (trackRenderer) trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms(); IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms(); // Make position relative to the transformed ancestor element. trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x()); trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y()); if (isHorizontal) { tickRect.setWidth(floor(tickSize.width() * zoomFactor)); tickRect.setHeight(floor(tickSize.height() * zoomFactor)); tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; tickRegionWidth = trackBounds.width() - thumbSize.width(); } else { tickRect.setWidth(floor(tickSize.height() * zoomFactor)); tickRect.setHeight(floor(tickSize.width() * zoomFactor)); tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; tickRegionWidth = trackBounds.height() - thumbSize.width(); } RefPtr<HTMLCollection> options = dataList->options(); GraphicsContextStateSaver stateSaver(*paintInfo.context); paintInfo.context->setFillColor(o->style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); for (unsigned i = 0; Node* node = options->item(i); i++) { ASSERT(isHTMLOptionElement(node)); HTMLOptionElement* optionElement = toHTMLOptionElement(node); String value = optionElement->value(); if (!input->isValidValue(value)) continue; double parsedValue = parseToDoubleForNumberType(input->sanitizeValue(value)); double tickFraction = (parsedValue - min) / (max - min); double tickRatio = isHorizontal && o->style()->isLeftToRightDirection() ? tickFraction : 1.0 - tickFraction; double tickPosition = round(tickRegionSideMargin + tickRegionWidth * tickRatio); if (isHorizontal) tickRect.setX(tickPosition); else tickRect.setY(tickPosition); paintInfo.context->fillRect(tickRect); } }
PassRefPtr<Uint8ClampedArray> getImageData(const IntRect& rect, const ImageBufferData& data, const IntSize& size) { RefPtr<Uint8ClampedArray> result = Uint8ClampedArray::createUninitialized(rect.width() * rect.height() * 4); if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height()) result->zeroFill(); int originx = rect.x(); int destx = 0; if (originx < 0) { destx = -originx; originx = 0; } int endx = rect.maxX(); if (endx > size.width()) endx = size.width(); int numColumns = endx - originx; int originy = rect.y(); int desty = 0; if (originy < 0) { desty = -originy; originy = 0; } int endy = rect.maxY(); if (endy > size.height()) endy = size.height(); int numRows = endy - originy; IntRect imageRect(originx, originy, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(data.m_surface.get(), imageRect); originx = imageRect.x(); originy = imageRect.y(); if (imageSurface != data.m_surface.get()) { IntRect area = intersection(rect, IntRect(0, 0, size.width(), size.height())); copyRectFromOneSurfaceToAnother(data.m_surface.get(), imageSurface.get(), IntSize(-area.x(), -area.y()), IntRect(IntPoint(), area.size()), IntSize(), CAIRO_OPERATOR_SOURCE); } unsigned char* dataSrc = cairo_image_surface_get_data(imageSurface.get()); unsigned char* dataDst = result->data(); int stride = cairo_image_surface_get_stride(imageSurface.get()); unsigned destBytesPerRow = 4 * rect.width(); unsigned char* destRows = dataDst + desty * destBytesPerRow + destx * 4; for (int y = 0; y < numRows; ++y) { unsigned* row = reinterpret_cast_ptr<unsigned*>(dataSrc + stride * (y + originy)); for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned* pixel = row + x + originx; // Avoid calling Color::colorFromPremultipliedARGB() because one // function call per pixel is too expensive. unsigned alpha = (*pixel & 0xFF000000) >> 24; unsigned red = (*pixel & 0x00FF0000) >> 16; unsigned green = (*pixel & 0x0000FF00) >> 8; unsigned blue = (*pixel & 0x000000FF); if (multiplied == Unmultiplied) { if (alpha && alpha != 255) { red = red * 255 / alpha; green = green * 255 / alpha; blue = blue * 255 / alpha; } } destRows[basex] = red; destRows[basex + 1] = green; destRows[basex + 2] = blue; destRows[basex + 3] = alpha; } destRows += destBytesPerRow; } return result.release(); }
FloatSize::FloatSize(const IntSize& size) : m_width(size.width()), m_height(size.height()) { }
void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url) { if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) return; bool inMainFrame = document()->frame() == document()->page()->mainFrame(); if (document()->isPluginDocument() && inMainFrame) { LOG(Plugins, "%p Plug-in document in main frame", this); return; } if (ScriptController::processingUserGesture()) { LOG(Plugins, "%p Script is processing user gesture, set to play", this); return; } if (m_createdDuringUserGesture) { LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this); return; } double lastKnownUserGestureTimestamp = document()->lastHandledUserGestureTimestamp(); if (!inMainFrame && document()->page()->mainFrame() && document()->page()->mainFrame()->document()) lastKnownUserGestureTimestamp = std::max(lastKnownUserGestureTimestamp, document()->page()->mainFrame()->document()->lastHandledUserGestureTimestamp()); if (currentTime() - lastKnownUserGestureTimestamp < autostartSoonAfterUserGestureThreshold) { LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this); return; } RenderBox* renderEmbeddedObject = toRenderBox(renderer()); Length styleWidth = renderEmbeddedObject->style()->width(); Length styleHeight = renderEmbeddedObject->style()->height(); LayoutRect contentBoxRect = renderEmbeddedObject->contentBoxRect(); int contentWidth = contentBoxRect.width(); int contentHeight = contentBoxRect.height(); int contentArea = contentWidth * contentHeight; IntSize visibleViewSize = document()->frame()->view()->visibleSize(); int visibleArea = visibleViewSize.width() * visibleViewSize.height(); if (inMainFrame && styleWidth.isPercent() && (styleWidth.percent() == 100) && styleHeight.isPercent() && (styleHeight.percent() == 100) && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) { LOG(Plugins, "%p Plug-in is top level full page, set to play", this); return; } if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) { LOG(Plugins, "%p Plug-in is %dx%d, set to play", this, contentWidth, contentHeight); return; } if (!document()->page() || !document()->page()->plugInClient()) { setDisplayState(WaitingForSnapshot); return; } LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); LOG(Plugins, " loaded URL: %s", url.string().utf8().data()); m_plugInOriginHash = PlugInOriginHash::hash(this, url); if (m_plugInOriginHash && document()->page()->plugInClient()->isAutoStartOrigin(m_plugInOriginHash)) { LOG(Plugins, "%p Plug-in hash %x is auto-start, set to play", this, m_plugInOriginHash); return; } LOG(Plugins, "%p Plug-in hash %x is %dx%d, origin is not auto-start, set to wait for snapshot", this, m_plugInOriginHash, contentWidth, contentHeight); // We may have got to this point by restarting a snapshotted plug-in, in which case we don't want to // reset the display state. if (displayState() != RestartingWithPendingMouseClick && displayState() != Restarting) setDisplayState(WaitingForSnapshot); }
ViewportAttributes computeViewportAttributes(ViewportArguments args, int desktopWidth, int deviceWidth, int deviceHeight, int deviceDPI, IntSize visibleViewport) { ViewportAttributes result; float availableWidth = visibleViewport.width(); float availableHeight = visibleViewport.height(); ASSERT(availableWidth > 0 && availableHeight > 0); switch (int(args.width)) { case ViewportArguments::ValueDesktopWidth: args.width = desktopWidth; break; case ViewportArguments::ValueDeviceWidth: args.width = deviceWidth; break; case ViewportArguments::ValueDeviceHeight: args.width = deviceHeight; break; } switch (int(args.height)) { case ViewportArguments::ValueDesktopWidth: args.height = desktopWidth; break; case ViewportArguments::ValueDeviceWidth: args.height = deviceWidth; break; case ViewportArguments::ValueDeviceHeight: args.height = deviceHeight; break; } result.devicePixelRatio = float(deviceDPI / 160.0); // Resolve non-'auto' width and height to pixel values. if (deviceDPI != 1.0) { deviceWidth /= result.devicePixelRatio; deviceHeight /= result.devicePixelRatio; if (args.width != ViewportArguments::ValueAuto) args.width /= result.devicePixelRatio; if (args.height != ViewportArguments::ValueAuto) args.height /= result.devicePixelRatio; } // Clamp values to range defined by spec and resolve minimum-scale and maximum-scale values if (args.width != ViewportArguments::ValueAuto) args.width = min(float(10000), max(args.width, float(1))); if (args.height != ViewportArguments::ValueAuto) args.height = min(float(10000), max(args.height, float(1))); if (args.initialScale != ViewportArguments::ValueAuto) args.initialScale = min(float(10), max(args.initialScale, float(0.1))); if (args.minimumScale != ViewportArguments::ValueAuto) args.minimumScale = min(float(10), max(args.minimumScale, float(0.1))); if (args.maximumScale != ViewportArguments::ValueAuto) args.maximumScale = min(float(10), max(args.maximumScale, float(0.1))); // Resolve minimum-scale and maximum-scale values according to spec. if (args.minimumScale == ViewportArguments::ValueAuto) result.minimumScale = float(0.25); else result.minimumScale = args.minimumScale; if (args.maximumScale == ViewportArguments::ValueAuto) { result.maximumScale = float(5.0); result.minimumScale = min(float(5.0), result.minimumScale); } else result.maximumScale = args.maximumScale; result.maximumScale = max(result.minimumScale, result.maximumScale); // Resolve initial-scale value. result.initialScale = args.initialScale; if (result.initialScale == ViewportArguments::ValueAuto) { result.initialScale = availableWidth / desktopWidth; if (args.width != ViewportArguments::ValueAuto) result.initialScale = availableWidth / args.width; if (args.height != ViewportArguments::ValueAuto) { // if 'auto', the initial-scale will be negative here and thus ignored. result.initialScale = max(result.initialScale, availableHeight / args.height); } } // Constrain initial-scale value to minimum-scale/maximum-scale range. result.initialScale = min(result.maximumScale, max(result.minimumScale, result.initialScale)); // Resolve width value. float width; if (args.width != ViewportArguments::ValueAuto) width = args.width; else { if (args.initialScale == ViewportArguments::ValueAuto) width = desktopWidth; else if (args.height != ViewportArguments::ValueAuto) width = args.height * (availableWidth / availableHeight); else width = availableWidth / result.initialScale; } // Resolve height value. float height; if (args.height != ViewportArguments::ValueAuto) height = args.height; else height = width * availableHeight / availableWidth; // Extend width and height to fill the visual viewport for the resolved initial-scale. width = max(width, availableWidth / result.initialScale); height = max(height, availableHeight / result.initialScale); result.layoutSize.setWidth(width); result.layoutSize.setHeight(height); // Update minimum scale factor, to never allow zooming out more than viewport result.minimumScale = max(result.minimumScale, max(availableWidth / width, availableHeight / height)); result.userScalable = args.userScalable; // Make maximum and minimum scale equal to the initial scale if user is not allowed to zoom in/out. if (!args.userScalable) result.maximumScale = result.minimumScale = result.initialScale; return result; }
String imageTitle(String const& filename, IntSize const& size) { return filename + " (" + String::number(size.width()) + "x" + String::number(size.height()) + ")"; }
void NativeImageSkia::drawPattern( GraphicsContext* context, const FloatRect& floatSrcRect, const FloatSize& scale, const FloatPoint& phase, CompositeOperator compositeOp, const FloatRect& destRect, blink::WebBlendMode blendMode, const IntSize& repeatSpacing) const { FloatRect normSrcRect = floatSrcRect; normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height())); if (destRect.isEmpty() || normSrcRect.isEmpty()) return; // nothing to draw SkMatrix totalMatrix = context->getTotalMatrix(); SkScalar ctmScaleX = totalMatrix.getScaleX(); SkScalar ctmScaleY = totalMatrix.getScaleY(); totalMatrix.preScale(scale.width(), scale.height()); // Figure out what size the bitmap will be in the destination. The // destination rect is the bounds of the pattern, we need to use the // matrix to see how big it will be. SkRect destRectTarget; totalMatrix.mapRect(&destRectTarget, normSrcRect); float destBitmapWidth = SkScalarToFloat(destRectTarget.width()); float destBitmapHeight = SkScalarToFloat(destRectTarget.height()); // Compute the resampling mode. ResamplingMode resampling; if (context->isAccelerated() || context->printing()) resampling = LinearResampling; else resampling = computeResamplingMode(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight); resampling = limitResamplingMode(context, resampling); SkMatrix shaderTransform; RefPtr<SkShader> shader; bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap()); // Bicubic filter is only applied to defer-decoded images, see // NativeImageSkia::draw for details. bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded; if (resampling == AwesomeResampling && !useBicubicFilter) { // Do nice resampling. float scaleX = destBitmapWidth / normSrcRect.width(); float scaleY = destBitmapHeight / normSrcRect.height(); SkRect scaledSrcRect; // The image fragment generated here is not exactly what is // requested. The scale factor used is approximated and image // fragment is slightly larger to align to integer // boundaries. SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect); if (repeatSpacing.isZero()) { shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); } else { shader = adoptRef(SkShader::CreateBitmapShader( createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); } // Since we just resized the bitmap, we need to remove the scale // applied to the pixels in the bitmap shader. This means we need // CTM * shaderTransform to have identity scale. Since we // can't modify CTM (or the rectangle will be drawn in the wrong // place), we must set shaderTransform's scale to the inverse of // CTM scale. shaderTransform.setScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1); } else { // No need to resample before drawing. SkBitmap srcSubset; bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect)); if (repeatSpacing.isZero()) { shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); } else { shader = adoptRef(SkShader::CreateBitmapShader( createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); } // Because no resizing occurred, the shader transform should be // set to the pattern's transform, which just includes scale. shaderTransform.setScale(scale.width(), scale.height()); } // We also need to translate it such that the origin of the pattern is the // origin of the destination rect, which is what WebKit expects. Skia uses // the coordinate system origin as the base for the pattern. If WebKit wants // a shifted image, it will shift it from there using the shaderTransform. float adjustedX = phase.x() + normSrcRect.x() * scale.width(); float adjustedY = phase.y() + normSrcRect.y() * scale.height(); shaderTransform.postTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY)); shader->setLocalMatrix(shaderTransform); SkPaint paint; paint.setShader(shader.get()); paint.setXfermode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode).get()); paint.setColorFilter(context->colorFilter()); paint.setFilterBitmap(resampling == LinearResampling); if (useBicubicFilter) paint.setFilterLevel(SkPaint::kHigh_FilterLevel); if (isLazyDecoded) PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID()); context->drawRect(destRect, paint); }
bool FECustomFilter::resizeMultisampleBuffers(const IntSize& newContextSize) { if (!m_triedMultisampleBuffer && !createMultisampleBuffer()) return false; if (!canUseMultisampleBuffers()) return false; static const int kMaxSampleCount = 4; int maxSupportedSampleCount = 0; m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSupportedSampleCount); int sampleCount = std::min(kMaxSampleCount, maxSupportedSampleCount); if (!sampleCount) { deleteMultisampleRenderBuffers(); return false; } Extensions3D* extensions = m_context->extensions(); ASSERT(extensions); m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFrameBuffer); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer); extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, Extensions3D::RGBA8_OES, newContextSize.width(), newContextSize.height()); m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleRenderBuffer); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer); extensions->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, GraphicsContext3D::DEPTH_COMPONENT16, newContextSize.width(), newContextSize.height()); m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_multisampleDepthBuffer); m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0); if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) { deleteMultisampleRenderBuffers(); return false; } return true; }
inline void FEGaussianBlur::platformApply(ByteArray* srcPixelArray, ByteArray* tmpPixelArray, unsigned kernelSizeX, unsigned kernelSizeY, IntSize& paintSize) { #if ENABLE(PARALLEL_JOBS) int scanline = 4 * paintSize.width(); int extraHeight = 3 * kernelSizeY * 0.5f; int optimalThreadNumber = (paintSize.width() * paintSize.height()) / (s_minimalRectDimension + extraHeight * paintSize.width()); if (optimalThreadNumber > 1) { ParallelJobs<PlatformApplyParameters> parallelJobs(&platformApplyWorker, optimalThreadNumber); int jobs = parallelJobs.numberOfJobs(); if (jobs > 1) { int blockHeight = paintSize.height() / jobs; --jobs; for (int job = jobs; job >= 0; --job) { PlatformApplyParameters& params = parallelJobs.parameter(job); params.filter = this; int startY; int endY; if (!job) { startY = 0; endY = blockHeight + extraHeight; params.srcPixelArray = srcPixelArray; params.dstPixelArray = tmpPixelArray; } else { if (job == jobs) { startY = job * blockHeight - extraHeight; endY = paintSize.height(); } else { startY = job * blockHeight - extraHeight; endY = (job + 1) * blockHeight + extraHeight; } int blockSize = (endY - startY) * scanline; params.srcPixelArray = ByteArray::create(blockSize); params.dstPixelArray = ByteArray::create(blockSize); memcpy(params.srcPixelArray->data(), srcPixelArray->data() + startY * scanline, blockSize); } params.width = paintSize.width(); params.height = endY - startY; params.kernelSizeX = kernelSizeX; params.kernelSizeY = kernelSizeY; } parallelJobs.execute(); // Copy together the parts of the image. for (int job = jobs; job >= 1; --job) { PlatformApplyParameters& params = parallelJobs.parameter(job); int sourceOffset; int destinationOffset; int size; if (job == jobs) { sourceOffset = extraHeight * scanline; destinationOffset = job * blockHeight * scanline; size = (paintSize.height() - job * blockHeight) * scanline; } else { sourceOffset = extraHeight * scanline; destinationOffset = job * blockHeight * scanline; size = blockHeight * scanline; } memcpy(srcPixelArray->data() + destinationOffset, params.srcPixelArray->data() + sourceOffset, size); } return; } } #endif // PARALLEL_JOBS // The selection here eventually should happen dynamically on some platforms. #if CPU(ARM_NEON) && COMPILER(GCC) platformApplyNeon(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); #else platformApplyGeneric(srcPixelArray, tmpPixelArray, kernelSizeX, kernelSizeY, paintSize); #endif }
void ChromeClient::widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSize) { #if USE(ACCELERATED_COMPOSITING) AcceleratedCompositingContext* compositingContext = m_webView->priv->acceleratedCompositingContext.get(); if (compositingContext->enabled()) { m_webView->priv->acceleratedCompositingContext->resizeRootLayer(newSize); return; } #endif // Grow the backing store by at least 1.5 times the current size. This prevents // lots of unnecessary allocations during an opaque resize. WidgetBackingStore* backingStore = m_webView->priv->backingStore.get(); if (backingStore && oldWidgetSize == newSize) return; if (backingStore) { const IntSize& oldSize = backingStore->size(); if (newSize.width() > oldSize.width()) newSize.setWidth(std::max(newSize.width(), static_cast<int>(oldSize.width() * 1.5))); if (newSize.height() > oldSize.height()) newSize.setHeight(std::max(newSize.height(), static_cast<int>(oldSize.height() * 1.5))); } // If we did not have a backing store before or if the backing store is growing, we need // to reallocate a new one and set it up so that we don't see artifacts while resizing. if (!backingStore || newSize.width() > backingStore->size().width() || newSize.height() > backingStore->size().height()) { OwnPtr<WidgetBackingStore> newBackingStore = createBackingStore(GTK_WIDGET(m_webView), newSize); RefPtr<cairo_t> cr = adoptRef(cairo_create(newBackingStore->cairoSurface())); clearEverywhereInBackingStore(m_webView, cr.get()); // Now we copy the old backing store image over the new cleared surface to prevent // annoying flashing as the widget grows. We do the "real" paint in a timeout // since we don't want to block resizing too long. if (backingStore) { cairo_set_source_surface(cr.get(), backingStore->cairoSurface(), 0, 0); cairo_rectangle(cr.get(), 0, 0, backingStore->size().width(), backingStore->size().height()); cairo_fill(cr.get()); } m_webView->priv->backingStore = newBackingStore.release(); backingStore = m_webView->priv->backingStore.get(); } else if (oldWidgetSize.width() < newSize.width() || oldWidgetSize.height() < newSize.height()) { // The widget is growing, but we did not need to create a new backing store. // We should clear any old data outside of the old widget region. RefPtr<cairo_t> cr = adoptRef(cairo_create(backingStore->cairoSurface())); clipOutOldWidgetArea(cr.get(), oldWidgetSize, newSize); clearEverywhereInBackingStore(m_webView, cr.get()); } // We need to force a redraw and ignore the framerate cap. m_lastDisplayTime = 0; m_dirtyRegion.unite(IntRect(IntPoint(), backingStore->size())); // WebCore timers by default have a lower priority which leads to more artifacts when opaque // resize is on, thus we use g_timeout_add here to force a higher timeout priority. if (!m_repaintSoonSourceId) m_repaintSoonSourceId = g_timeout_add(0, reinterpret_cast<GSourceFunc>(repaintEverythingSoonTimeout), this); }
void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size) { LOG(Media, "MediaPlayerPrivateAVFoundation:setNaturalSize(%p) - size = %d x %d", this, size.width(), size.height()); IntSize oldSize = m_cachedNaturalSize; m_cachedNaturalSize = size; if (oldSize != m_cachedNaturalSize) m_player->sizeChanged(); }
static ResamplingMode computeResamplingMode(PlatformContextSkia* platformContext, const NativeImageSkia& bitmap, int srcWidth, int srcHeight, float destWidth, float destHeight) { if (platformContext->hasImageResamplingHint()) { IntSize srcSize; FloatSize dstSize; platformContext->getImageResamplingHint(&srcSize, &dstSize); srcWidth = srcSize.width(); srcHeight = srcSize.height(); destWidth = dstSize.width(); destHeight = dstSize.height(); } 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. // If the platform context permits high quality interpolation, use it. if (platformContext->interpolationQuality() == InterpolationHigh) return RESAMPLE_AWESOME; return RESAMPLE_LINEAR; }
bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) { ASSERT(src); ASSERT(clipboard); if (!src->view() || !src->contentRenderer()) return false; HitTestResult dragSource = HitTestResult(dragOrigin); dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); KURL linkURL = dragSource.absoluteLinkURL(); KURL imageURL = dragSource.absoluteImageURL(); bool isSelected = dragSource.isSelected(); IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos()); m_draggingImageURL = KURL(); m_dragOperation = srcOp; DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); if (isDHTMLDrag) dragImage = clipboard->createDragImage(dragImageOffset); // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. if (dragImage) { dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); m_dragOffset = dragImageOffset; } bool startedDrag = true; // optimism - we almost always manage to start the drag Node* node = dragSource.innerNonSharedNode(); Image* image = getImage(static_cast<Element*>(node)); if (!imageURL.isEmpty() && node && node->isElementNode() && image && (m_dragSourceAction & DragSourceActionImage)) { // We shouldn't be starting a drag for an image that can't provide an extension. // This is an early detection for problems encountered later upon drop. ASSERT(!image->filenameExtension().isEmpty()); Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString()); } m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); if (!dragImage) { IntRect imageRect = dragSource.imageRect(); imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location()))); doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset); } else // DHTML defined drag image doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { if (!clipboard->hasData()) // Simplify whitespace so the title put on the clipboard resembles what the user sees // on the web page. This includes replacing newlines with spaces. clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src); if (src->selection()->isCaret() && src->selection()->isContentEditable()) { // a user can initiate a drag on a link without having any text // selected. In this case, we should expand the selection to // the enclosing anchor element Position pos = src->selection()->base(); Node* node = enclosingAnchorElement(pos); if (node) src->selection()->setSelection(Selection::selectionFromContentsOfNode(node)); } m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); if (!dragImage) { dragImage = m_client->createDragImageForLink(linkURL, dragSource.textContent(), src); IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); ASSERT(selectionRange); if (!clipboard->hasData()) clipboard->writeRange(selectionRange.get(), src); m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForSelection(src); dragLoc = dragLocForSelectionDrag(src); m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y())); } doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (isDHTMLDrag) { ASSERT(m_dragSourceAction & DragSourceActionDHTML); m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else { // Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty. startedDrag = false; } if (dragImage) deleteDragImage(dragImage); return startedDrag; }
// used by the partial screen invals FloatRect ShaderProgram::rectInViewCoord(const TransformationMatrix& drawMatrix, const IntSize& size) { FloatRect srect(0, 0, size.width(), size.height()); TransformationMatrix renderMatrix = m_contentToViewMatrix * drawMatrix; return renderMatrix.mapRect(srect); }
void NinePieceImageGrid::setDrawInfoMiddle(NinePieceDrawInfo& drawInfo) const { IntSize sourceSize = m_imageSize - IntSize(m_left.slice + m_right.slice, m_top.slice + m_bottom.slice); IntSize destinationSize = m_borderImageArea.size() - IntSize(m_left.width + m_right.width, m_top.width + m_bottom.width); drawInfo.isDrawable = m_fill && !sourceSize.isEmpty() && !destinationSize.isEmpty(); if (!drawInfo.isDrawable) return; drawInfo.source = subrect(m_imageSize, m_left.slice, m_top.slice, sourceSize.width(), sourceSize.height()); drawInfo.destination = subrect(m_borderImageArea, m_left.width, m_top.width, destinationSize.width(), destinationSize.height()); FloatSize middleScaleFactor(1, 1); if (m_top.isDrawable()) middleScaleFactor.setWidth(m_top.scale()); else if (m_bottom.isDrawable()) middleScaleFactor.setWidth(m_bottom.scale()); if (m_left.isDrawable()) middleScaleFactor.setHeight(m_left.scale()); else if (m_right.isDrawable()) middleScaleFactor.setHeight(m_right.scale()); if (!sourceSize.isEmpty()) { // For "stretch" rules, just override the scale factor and replace. We only have to do this for the center tile, // since sides don't even use the scale factor unless they have a rule other than "stretch". The middle however // can have "stretch" specified in one axis but not the other, so we have to correct the scale here. if (m_horizontalTileRule == (Image::TileRule)StretchImageRule) middleScaleFactor.setWidth((float) destinationSize.width() / sourceSize.width()); if (m_verticalTileRule == (Image::TileRule)StretchImageRule) middleScaleFactor.setHeight((float) destinationSize.height() / sourceSize.height()); } drawInfo.tileScale = middleScaleFactor; drawInfo.tileRule = { m_horizontalTileRule, m_verticalTileRule }; }
PlatformGestureEventBuilder::PlatformGestureEventBuilder(Widget* widget, const WebGestureEvent& e) { float scale = widgetInputEventsScaleFactor(widget); IntSize offset = widgetInputEventsOffset(widget); IntPoint pinchViewport = pinchViewportOffset(widget); switch (e.type) { case WebInputEvent::GestureScrollBegin: m_type = PlatformEvent::GestureScrollBegin; break; case WebInputEvent::GestureScrollEnd: m_type = PlatformEvent::GestureScrollEnd; break; case WebInputEvent::GestureFlingStart: m_type = PlatformEvent::GestureFlingStart; break; case WebInputEvent::GestureScrollUpdate: m_type = PlatformEvent::GestureScrollUpdate; m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; break; case WebInputEvent::GestureScrollUpdateWithoutPropagation: m_type = PlatformEvent::GestureScrollUpdateWithoutPropagation; m_data.m_scrollUpdate.m_deltaX = e.data.scrollUpdate.deltaX / scale; m_data.m_scrollUpdate.m_deltaY = e.data.scrollUpdate.deltaY / scale; m_data.m_scrollUpdate.m_velocityX = e.data.scrollUpdate.velocityX; m_data.m_scrollUpdate.m_velocityY = e.data.scrollUpdate.velocityY; break; case WebInputEvent::GestureTap: m_type = PlatformEvent::GestureTap; m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); m_data.m_tap.m_tapCount = e.data.tap.tapCount; break; case WebInputEvent::GestureTapUnconfirmed: m_type = PlatformEvent::GestureTapUnconfirmed; m_area = expandedIntSize(FloatSize(e.data.tap.width / scale, e.data.tap.height / scale)); break; case WebInputEvent::GestureTapDown: m_type = PlatformEvent::GestureTapDown; m_area = expandedIntSize(FloatSize(e.data.tapDown.width / scale, e.data.tapDown.height / scale)); break; case WebInputEvent::GestureShowPress: m_type = PlatformEvent::GestureShowPress; m_area = expandedIntSize(FloatSize(e.data.showPress.width / scale, e.data.showPress.height / scale)); break; case WebInputEvent::GestureTapCancel: m_type = PlatformEvent::GestureTapDownCancel; break; case WebInputEvent::GestureDoubleTap: // DoubleTap gesture is now handled as PlatformEvent::GestureTap with tap_count = 2. So no // need to convert to a Platfrom DoubleTap gesture. But in WebViewImpl::handleGestureEvent // all WebGestureEvent are converted to PlatformGestureEvent, for completeness and not reach // the ASSERT_NOT_REACHED() at the end, convert the DoubleTap to a NoType. m_type = PlatformEvent::NoType; break; case WebInputEvent::GestureTwoFingerTap: m_type = PlatformEvent::GestureTwoFingerTap; m_area = expandedIntSize(FloatSize(e.data.twoFingerTap.firstFingerWidth / scale, e.data.twoFingerTap.firstFingerHeight / scale)); break; case WebInputEvent::GestureLongPress: m_type = PlatformEvent::GestureLongPress; m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); break; case WebInputEvent::GestureLongTap: m_type = PlatformEvent::GestureLongTap; m_area = expandedIntSize(FloatSize(e.data.longPress.width / scale, e.data.longPress.height / scale)); break; case WebInputEvent::GesturePinchBegin: m_type = PlatformEvent::GesturePinchBegin; break; case WebInputEvent::GesturePinchEnd: m_type = PlatformEvent::GesturePinchEnd; break; case WebInputEvent::GesturePinchUpdate: m_type = PlatformEvent::GesturePinchUpdate; m_data.m_pinchUpdate.m_scale = e.data.pinchUpdate.scale; break; default: ASSERT_NOT_REACHED(); } m_position = widget->convertFromContainingWindow( IntPoint((e.x - offset.width()) / scale + pinchViewport.x(), (e.y - offset.height()) / scale + pinchViewport.y())); m_globalPosition = IntPoint(e.globalX, e.globalY); m_timestamp = e.timeStampSeconds; m_modifiers = 0; if (e.modifiers & WebInputEvent::ShiftKey) m_modifiers |= PlatformEvent::ShiftKey; if (e.modifiers & WebInputEvent::ControlKey) m_modifiers |= PlatformEvent::CtrlKey; if (e.modifiers & WebInputEvent::AltKey) m_modifiers |= PlatformEvent::AltKey; if (e.modifiers & WebInputEvent::MetaKey) m_modifiers |= PlatformEvent::MetaKey; }
void SVGImage::drawSVGToImageBuffer(ImageBuffer* buffer, const IntSize& size, float zoom, float scale, ShouldClearBuffer shouldClear) { // FIXME: This doesn't work correctly with animations. If an image contains animations, that say run for 2 seconds, // and we currently have one <img> that displays us. If we open another document referencing the same SVGImage it // will display the document at a time where animations already ran - even though it has its own ImageBuffer. // We currently don't implement SVGSVGElement::setCurrentTime, and can NOT go back in time, once animations started. // There's no way to fix this besides avoiding style/attribute mutations from SVGAnimationElement. ASSERT(buffer); ASSERT(!size.isEmpty()); if (!m_page) return; Frame* frame = m_page->mainFrame(); SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement(); if (!rootElement) return; RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer()); if (!renderer) return; // Draw image at requested size. ImageObserver* observer = imageObserver(); ASSERT(observer); // Temporarily reset image observer, we don't want to receive any changeInRect() calls due to this relayout. setImageObserver(0); // Disable repainting; we don't want deferred repaints to schedule any timers due to this relayout. frame->view()->beginDisableRepaints(); renderer->setContainerSize(size); frame->view()->resize(this->size()); if (zoom != 1) frame->setPageZoomFactor(zoom); // Eventually clear image buffer. IntRect rect(IntPoint(), size); FloatRect scaledRect(rect); scaledRect.scale(scale); if (shouldClear == ClearImageBuffer) buffer->context()->clearRect(enclosingIntRect(scaledRect)); // Draw SVG on top of ImageBuffer. draw(buffer->context(), enclosingIntRect(scaledRect), rect, ColorSpaceDeviceRGB, CompositeSourceOver, BlendModeNormal); // Reset container size & zoom to initial state. Otherwhise the size() of this // image would return whatever last size was set by drawSVGToImageBuffer(). if (zoom != 1) frame->setPageZoomFactor(1); // Renderer may have been recreated by frame->setPageZoomFactor(zoom). So fetch it again. renderer = toRenderSVGRoot(rootElement->renderer()); if (renderer) renderer->setContainerSize(IntSize()); frame->view()->resize(this->size()); if (frame->view()->needsLayout()) frame->view()->layout(); setImageObserver(observer); frame->view()->endDisableRepaints(); }
unsigned LayerPool::backingStoreBytesForSize(const IntSize& size) { return size.width() * size.height() * 4; }
ImageData::ImageData(const IntSize& size) : m_size(size) , m_data(Uint8ClampedArray::createUninitialized(size.width() * size.height() * 4)) { ScriptWrappable::init(this); }
void FrameViewAutoSizeInfo::autoSizeIfNeeded() { if (m_inAutoSize) return; TemporaryChange<bool> changeInAutoSize(m_inAutoSize, true); Document* document = m_frameView->frame().document(); if (!document || !document->isActive()) return; Element* documentElement = document->documentElement(); if (!documentElement) return; // If this is the first time we run autosize, start from small height and // allow it to grow. if (!m_didRunAutosize) m_frameView->resize(m_frameView->frameRect().width(), m_minAutoSize.height()); IntSize size = m_frameView->frameRect().size(); // Do the resizing twice. The first time is basically a rough calculation using the preferred width // which may result in a height change during the second iteration. for (int i = 0; i < 2; i++) { // Update various sizes including contentsSize, scrollHeight, etc. document->updateLayoutIgnorePendingStylesheets(); RenderView* renderView = document->renderView(); if (!renderView) return; int width = renderView->minPreferredLogicalWidth(); RenderBox* documentRenderBox = documentElement->renderBox(); if (!documentRenderBox) return; int height = documentRenderBox->scrollHeight(); IntSize newSize(width, height); // Check to see if a scrollbar is needed for a given dimension and // if so, increase the other dimension to account for the scrollbar. // Since the dimensions are only for the view rectangle, once a // dimension exceeds the maximum, there is no need to increase it further. if (newSize.width() > m_maxAutoSize.width()) { RefPtrWillBeRawPtr<Scrollbar> localHorizontalScrollbar = m_frameView->horizontalScrollbar(); if (!localHorizontalScrollbar) localHorizontalScrollbar = m_frameView->createScrollbar(HorizontalScrollbar); if (!localHorizontalScrollbar->isOverlayScrollbar()) newSize.setHeight(newSize.height() + localHorizontalScrollbar->height()); // Don't bother checking for a vertical scrollbar because the width is at // already greater the maximum. } else if (newSize.height() > m_maxAutoSize.height()) { RefPtrWillBeRawPtr<Scrollbar> localVerticalScrollbar = m_frameView->verticalScrollbar(); if (!localVerticalScrollbar) localVerticalScrollbar = m_frameView->createScrollbar(VerticalScrollbar); if (!localVerticalScrollbar->isOverlayScrollbar()) newSize.setWidth(newSize.width() + localVerticalScrollbar->width()); // Don't bother checking for a horizontal scrollbar because the height is // already greater the maximum. } // Ensure the size is at least the min bounds. newSize = newSize.expandedTo(m_minAutoSize); // Bound the dimensions by the max bounds and determine what scrollbars to show. ScrollbarMode horizonalScrollbarMode = ScrollbarAlwaysOff; if (newSize.width() > m_maxAutoSize.width()) { newSize.setWidth(m_maxAutoSize.width()); horizonalScrollbarMode = ScrollbarAlwaysOn; } ScrollbarMode verticalScrollbarMode = ScrollbarAlwaysOff; if (newSize.height() > m_maxAutoSize.height()) { newSize.setHeight(m_maxAutoSize.height()); verticalScrollbarMode = ScrollbarAlwaysOn; } if (newSize == size) continue; // While loading only allow the size to increase (to avoid twitching during intermediate smaller states) // unless autoresize has just been turned on or the maximum size is smaller than the current size. if (m_didRunAutosize && size.height() <= m_maxAutoSize.height() && size.width() <= m_maxAutoSize.width() && !m_frameView->frame().document()->loadEventFinished() && (newSize.height() < size.height() || newSize.width() < size.width())) break; m_frameView->resize(newSize.width(), newSize.height()); // Force the scrollbar state to avoid the scrollbar code adding them and causing them to be needed. For example, // a vertical scrollbar may cause text to wrap and thus increase the height (which is the only reason the scollbar is needed). m_frameView->setVerticalScrollbarLock(false); m_frameView->setHorizontalScrollbarLock(false); m_frameView->setScrollbarModes(horizonalScrollbarMode, verticalScrollbarMode, true, true); } m_didRunAutosize = true; }
void DrawingAreaImpl::display(UpdateInfo& updateInfo) { ASSERT(!m_isPaintingSuspended); ASSERT(!m_layerTreeHost); ASSERT(!m_webPage->size().isEmpty()); // FIXME: It would be better if we could avoid painting altogether when there is a custom representation. if (m_webPage->mainFrameHasCustomRepresentation()) { // ASSUMPTION: the custom representation will be painting the dirty region for us. m_dirtyRegion = Region(); return; } m_webPage->layoutIfNeeded(); // The layout may have put the page into accelerated compositing mode. If the LayerTreeHost is // in charge of displaying, we have nothing more to do. if (m_layerTreeHost) return; updateInfo.viewSize = m_webPage->size(); updateInfo.deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor(); IntRect bounds = m_dirtyRegion.bounds(); ASSERT(m_webPage->bounds().contains(bounds)); IntSize bitmapSize = bounds.size(); float deviceScaleFactor = m_webPage->corePage()->deviceScaleFactor(); bitmapSize.scale(deviceScaleFactor); RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(bitmapSize, ShareableBitmap::SupportsAlpha); if (!bitmap) return; if (!bitmap->createHandle(updateInfo.bitmapHandle)) return; Vector<IntRect> rects = m_dirtyRegion.rects(); if (shouldPaintBoundsRect(bounds, rects)) { rects.clear(); rects.append(bounds); } updateInfo.scrollRect = m_scrollRect; updateInfo.scrollOffset = m_scrollOffset; m_dirtyRegion = Region(); m_scrollRect = IntRect(); m_scrollOffset = IntSize(); OwnPtr<GraphicsContext> graphicsContext = createGraphicsContext(bitmap.get()); graphicsContext->applyDeviceScaleFactor(deviceScaleFactor); updateInfo.updateRectBounds = bounds; graphicsContext->translate(-bounds.x(), -bounds.y()); for (size_t i = 0; i < rects.size(); ++i) { m_webPage->drawRect(*graphicsContext, rects[i]); if (m_webPage->hasPageOverlay()) m_webPage->drawPageOverlay(*graphicsContext, rects[i]); updateInfo.updateRects.append(rects[i]); } // Layout can trigger more calls to setNeedsDisplay and we don't want to process them // until the UI process has painted the update, so we stop the timer here. m_displayTimer.stop(); }
bool GraphicsContext3D::reshapeFBOs(const IntSize& size) { const int width = size.width(); const int height = size.height(); GLuint colorFormat, internalDepthStencilFormat = 0; if (m_attrs.alpha) { m_internalColorFormat = GL_RGBA8; colorFormat = GL_RGBA; } else { m_internalColorFormat = GL_RGB8; colorFormat = GL_RGB; } if (m_attrs.stencil || m_attrs.depth) { // We don't allow the logic where stencil is required and depth is not. // See GraphicsContext3D::validateAttributes. Extensions3D* extensions = getExtensions(); // Use a 24 bit depth buffer where we know we have it. if (extensions->supports("GL_EXT_packed_depth_stencil")) internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT; else internalDepthStencilFormat = GL_DEPTH_COMPONENT; } bool mustRestoreFBO = false; // Resize multisample FBO. if (m_attrs.antialias) { GLint maxSampleCount; ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount); GLint sampleCount = std::min(8, maxSampleCount); if (sampleCount > maxSampleCount) sampleCount = maxSampleCount; if (m_boundFBO != m_multisampleFBO) { ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); mustRestoreFBO = true; } ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height); ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer); if (m_attrs.stencil || m_attrs.depth) { ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height); if (m_attrs.stencil) ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); if (m_attrs.depth) ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer); } ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { // FIXME: cleanup. notImplemented(); } } // resize regular FBO if (m_boundFBO != m_fbo) { mustRestoreFBO = true; ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); } ::glBindTexture(GL_TEXTURE_2D, m_texture); ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0); ::glBindTexture(GL_TEXTURE_2D, 0); if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) { ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer); ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height); if (m_attrs.stencil) ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); if (m_attrs.depth) ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer); ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) { // FIXME: cleanup notImplemented(); } if (m_attrs.antialias) { ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO); if (m_boundFBO == m_multisampleFBO) mustRestoreFBO = false; } return mustRestoreFBO; }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; int drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == cTextFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { IntSize size; int blur; Color color; graphicsContext->getShadow(size, blur, color); drawIntoBitmap = !size.isEmpty() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. int lineGap = font->lineGap(); textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing()); bitmap.set(graphicsContext->createWindowsBitmap(textRect.size())); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == cTextFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->syntheticBoldOffset()) { xform.eM21 = 0; xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { XFORM xform; GetWorldTransform(hdc, &xform); TransformationMatrix hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); if (drawingMode & cTextFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & cTextStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } CGContextRestoreGState(cgContext); CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }
bool GraphicsContext3D::ImageExtractor::extractImage(bool premultiplyAlpha, bool ignoreGammaAndColorProfile) { if (!m_image) return false; // We need this to stay in scope because the native image is just a shallow copy of the data. AlphaOption alphaOption = premultiplyAlpha ? AlphaOption::Premultiplied : AlphaOption::NotPremultiplied; GammaAndColorProfileOption gammaAndColorProfileOption = ignoreGammaAndColorProfile ? GammaAndColorProfileOption::Ignored : GammaAndColorProfileOption::Applied; m_decoder = new ImageSource(nullptr, alphaOption, gammaAndColorProfileOption); if (!m_decoder) return false; ImageSource& decoder = *m_decoder; m_alphaOp = AlphaDoNothing; if (m_image->data()) { decoder.setData(m_image->data(), true); if (!decoder.frameCount()) return false; m_imageSurface = decoder.createFrameImageAtIndex(0); } else { m_imageSurface = m_image->nativeImageForCurrentFrame(); // 1. For texImage2D with HTMLVideoElment input, assume no PremultiplyAlpha had been applied and the alpha value is 0xFF for each pixel, // which is true at present and may be changed in the future and needs adjustment accordingly. // 2. For texImage2D with HTMLCanvasElement input in which Alpha is already Premultiplied in this port, // do AlphaDoUnmultiply if UNPACK_PREMULTIPLY_ALPHA_WEBGL is set to false. if (!premultiplyAlpha && m_imageHtmlDomSource != HtmlDomVideo) m_alphaOp = AlphaDoUnmultiply; // if m_imageSurface is not an image, extract a copy of the surface if (m_imageSurface && cairo_surface_get_type(m_imageSurface.get()) != CAIRO_SURFACE_TYPE_IMAGE) { IntSize surfaceSize = cairoSurfaceSize(m_imageSurface.get()); auto tmpSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, surfaceSize.width(), surfaceSize.height())); copyRectFromOneSurfaceToAnother(m_imageSurface.get(), tmpSurface.get(), IntSize(), IntRect(IntPoint(), surfaceSize), IntSize(), CAIRO_OPERATOR_SOURCE); m_imageSurface = WTFMove(tmpSurface); } } if (!m_imageSurface) return false; ASSERT(cairo_surface_get_type(m_imageSurface.get()) == CAIRO_SURFACE_TYPE_IMAGE); IntSize imageSize = cairoSurfaceSize(m_imageSurface.get()); m_imageWidth = imageSize.width(); m_imageHeight = imageSize.height(); if (!m_imageWidth || !m_imageHeight) return false; if (cairo_image_surface_get_format(m_imageSurface.get()) != CAIRO_FORMAT_ARGB32) return false; unsigned int srcUnpackAlignment = 1; size_t bytesPerRow = cairo_image_surface_get_stride(m_imageSurface.get()); size_t bitsPerPixel = 32; unsigned padding = bytesPerRow - bitsPerPixel / 8 * m_imageWidth; if (padding) { srcUnpackAlignment = padding + 1; while (bytesPerRow % srcUnpackAlignment) ++srcUnpackAlignment; } m_imagePixelData = cairo_image_surface_get_data(m_imageSurface.get()); m_imageSourceFormat = DataFormatBGRA8; m_imageSourceUnpackAlignment = srcUnpackAlignment; return true; }
void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { CGContextRef cgContext = graphicsContext->platformContext(); bool shouldUseFontSmoothing = WebCoreShouldUseFontSmoothing(); if (font->platformData().useGDI()) { if (!shouldUseFontSmoothing || (graphicsContext->textDrawingMode() & cTextStroke)) { drawGDIGlyphs(graphicsContext, font, glyphBuffer, from, numGlyphs, point); return; } } uint32_t oldFontSmoothingStyle = wkSetFontSmoothingStyle(cgContext, shouldUseFontSmoothing); const FontPlatformData& platformData = font->platformData(); CGContextSetFont(cgContext, platformData.cgFont()); CGAffineTransform matrix = CGAffineTransformIdentity; matrix.b = -matrix.b; matrix.d = -matrix.d; if (platformData.syntheticOblique()) { static float skew = -tanf(syntheticObliqueAngle * piFloat / 180.0f); matrix = CGAffineTransformConcat(matrix, CGAffineTransformMake(1, 0, skew, 1, 0, 0)); } CGContextSetTextMatrix(cgContext, matrix); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); CGContextSetFontSize(cgContext, platformData.size()); wkSetCGContextFontRenderingStyle(cgContext, font->isSystemFont(), false, font->platformData().useGDI()); IntSize shadowSize; int shadowBlur; Color shadowColor; graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor); bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur; if (hasSimpleShadow) { // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing. graphicsContext->clearShadow(); Color fillColor = graphicsContext->fillColor(); Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); graphicsContext->setFillColor(shadowFillColor); CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + translation.height() + shadowSize.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } graphicsContext->setFillColor(fillColor); } CGContextSetTextPosition(cgContext, point.x() + translation.width(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); if (font->syntheticBoldOffset()) { CGContextSetTextPosition(cgContext, point.x() + translation.width() + font->syntheticBoldOffset(), point.y() + translation.height()); CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs); } if (hasSimpleShadow) graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor); wkRestoreFontSmoothingStyle(cgContext, oldFontSmoothingStyle); }
void ChromeClientEfl::contentsSizeChanged(Frame* frame, const IntSize& size) const { ewk_frame_contents_size_changed(kit(frame), size.width(), size.height()); if (ewk_view_frame_main_get(m_view) == kit(frame)) ewk_view_contents_size_changed(m_view, size.width(), size.height()); }
DragImageRef WebDragClient::createDragImageForLink(KURL& url, const String& inLabel, Frame* frame) { // This is more or less an exact match for the Mac OS X code. const Font* labelFont; const Font* urlFont; if (frame->settings() && frame->settings()->fontRenderingMode() == AlternateRenderingMode) { static const Font alternateRenderingModeLabelFont = dragLabelFont(DRAG_LINK_LABEL_FONT_SIZE, true, AlternateRenderingMode); static const Font alternateRenderingModeURLFont = dragLabelFont(DRAG_LINK_URL_FONT_SIZE, false, AlternateRenderingMode); labelFont = &alternateRenderingModeLabelFont; urlFont = &alternateRenderingModeURLFont; } else { static const Font normalRenderingModeLabelFont = dragLabelFont(DRAG_LINK_LABEL_FONT_SIZE, true, NormalRenderingMode); static const Font normalRenderingModeURLFont = dragLabelFont(DRAG_LINK_URL_FONT_SIZE, false, NormalRenderingMode); labelFont = &normalRenderingModeLabelFont; urlFont = &normalRenderingModeURLFont; } bool drawURLString = true; bool clipURLString = false; bool clipLabelString = false; String urlString = url.string(); String label = inLabel; if (label.isEmpty()) { drawURLString = false; label = urlString; } //First step in drawing the link drag image width TextRun labelRun(label.impl()); TextRun urlRun(urlString.impl()); IntSize labelSize(labelFont->width(labelRun), labelFont->fontMetrics().ascent() + labelFont->fontMetrics().descent()); if (labelSize.width() > MAX_DRAG_LABEL_STRING_WIDTH){ labelSize.setWidth(MAX_DRAG_LABEL_STRING_WIDTH); clipLabelString = true; } IntSize urlStringSize; IntSize imageSize(labelSize.width() + DRAG_LABEL_BORDER_X * 2, labelSize.height() + DRAG_LABEL_BORDER_Y * 2); if (drawURLString) { urlStringSize.setWidth(urlFont->width(urlRun)); urlStringSize.setHeight(urlFont->fontMetrics().ascent() + urlFont->fontMetrics().descent()); imageSize.setHeight(imageSize.height() + urlStringSize.height()); if (urlStringSize.width() > MAX_DRAG_LABEL_STRING_WIDTH) { imageSize.setWidth(MAX_DRAG_LABEL_WIDTH); clipURLString = true; } else { imageSize.setWidth(std::max(labelSize.width(), urlStringSize.width()) + DRAG_LABEL_BORDER_X * 2); } } // We now know how big the image needs to be, so we create and // fill the background HBITMAP image = 0; HDC dc = GetDC(0); HDC workingDC = CreateCompatibleDC(dc); if (!workingDC) { ReleaseDC(0, dc); return 0; } PlatformGraphicsContext* contextRef; image = allocImage(workingDC, imageSize, &contextRef); if (!image) { DeleteDC(workingDC); ReleaseDC(0, dc); return 0; } ::SelectObject(workingDC, image); GraphicsContext context(contextRef); // On Mac alpha is {0.7, 0.7, 0.7, 0.8}, however we can't control alpha // for drag images on win, so we use 1 static const Color backgroundColor(140, 140, 140); static const IntSize radii(DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS); IntRect rect(0, 0, imageSize.width(), imageSize.height()); context.fillRoundedRect(rect, radii, radii, radii, radii, backgroundColor, ColorSpaceDeviceRGB); // Draw the text static const Color topColor(0, 0, 0, 255); //original alpha = 0.75 static const Color bottomColor(255, 255, 255, 127); //original alpha = 0.5 if (drawURLString) { if (clipURLString) urlString = StringTruncator::rightTruncate(urlString, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), *urlFont, false); IntPoint textPos(DRAG_LABEL_BORDER_X, imageSize.height() - (DRAG_LABEL_BORDER_Y_OFFSET + urlFont->fontMetrics().descent())); WebCoreDrawDoubledTextAtPoint(context, urlString, textPos, *urlFont, topColor, bottomColor); } if (clipLabelString) label = StringTruncator::rightTruncate(label, imageSize.width() - (DRAG_LABEL_BORDER_X * 2.0f), *labelFont, false); IntPoint textPos(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y + labelFont->pixelSize()); WebCoreDrawDoubledTextAtPoint(context, label, textPos, *labelFont, topColor, bottomColor); deallocContext(contextRef); DeleteDC(workingDC); ReleaseDC(0, dc); return image; }
void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.maxX()); int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.maxY()); int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; IntRect imageRect(destx, desty, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(m_data.m_surface.get(), imageRect); destx = imageRect.x(); desty = imageRect.y(); unsigned char* pixelData = cairo_image_surface_get_data(imageSurface.get()); unsigned srcBytesPerRow = 4 * sourceSize.width(); int stride = cairo_image_surface_get_stride(imageSurface.get()); unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { unsigned* row = reinterpret_cast_ptr<unsigned*>(pixelData + stride * (y + desty)); for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned* pixel = row + x + destx; // Avoid calling Color::premultipliedARGBFromColor() because one // function call per pixel is too expensive. unsigned red = srcRows[basex]; unsigned green = srcRows[basex + 1]; unsigned blue = srcRows[basex + 2]; unsigned alpha = srcRows[basex + 3]; if (multiplied == Unmultiplied) { if (alpha != 255) { red = (red * alpha + 254) / 255; green = (green * alpha + 254) / 255; blue = (blue * alpha + 254) / 255; } } *pixel = (alpha << 24) | red << 16 | green << 8 | blue; } srcRows += srcBytesPerRow; } cairo_surface_mark_dirty_rectangle(imageSurface.get(), destx, desty, numColumns, numRows); if (imageSurface != m_data.m_surface.get()) copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, numColumns, numRows), IntSize(destPoint.x() + sourceRect.x(), destPoint.y() + sourceRect.y()), CAIRO_OPERATOR_SOURCE); }
FloatSize DragImage::clampedImageScale(const IntSize& imageSize, const IntSize& size, const IntSize& maxSize) { // Non-uniform scaling for size mapping. FloatSize imageScale( static_cast<float>(size.width()) / imageSize.width(), static_cast<float>(size.height()) / imageSize.height()); // Uniform scaling for clamping. const float clampScaleX = size.width() > maxSize.width() ? static_cast<float>(maxSize.width()) / size.width() : 1; const float clampScaleY = size.height() > maxSize.height() ? static_cast<float>(maxSize.height()) / size.height() : 1; imageScale.scale(std::min(clampScaleX, clampScaleY)); return imageScale; }