diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/src/main/resources/PDFExportIT/Parent/Child/WebHome.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/src/main/resources/PDFExportIT/Parent/Child/WebHome.xml index 86682cb40e0d..da67cdad7fcf 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/src/main/resources/PDFExportIT/Parent/Child/WebHome.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-content/src/main/resources/PDFExportIT/Parent/Child/WebHome.xml @@ -40,7 +40,15 @@ Content of first section. -[[image:attach:xwiki-logo.png||width="100"]] +[[image:attach:xwiki-logo.png||width="100"]] + +[[image:attach:xwiki-logo.png||width="100" class="force-server-side-resize"]] + +{{velocity}} +{{html}} +<img src="$doc.getAttachmentURL('xwiki-logo.png', 'download', 'height=50')" alt="XWiki Logo" /> +{{/html}} +{{/velocity}} xwiki-logo.png image/png diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java index 5a166da15232..180b95ef2b33 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java @@ -226,14 +226,20 @@ void exportAsPDF(TestUtils setup, TestConfiguration testConfiguration) throws Ex assertTrue(contentPageText.contains("Child\nSection 1\nContent of first section.\n"), "Child document content missing: " + contentPageText); - // The content of the child document shows an image. + // The content of the child document shows the same image multiple times. List contentPageImages = pdf.getImagesFromPage(3); - assertEquals(1, contentPageImages.size()); + assertEquals(3, contentPageImages.size()); - // Verify the image included in the PDF is not resized server-side (we know the image width is specified in - // the source wiki syntax and we enabled the server-side image resize by default). + // Verify the images included in the PDF are not resized server-side (we know the image width is specified + // in the source wiki syntax and we enabled the server-side image resize by default). assertEquals(512, contentPageImages.get(0).getRawWidth()); assertEquals(512, contentPageImages.get(0).getRawHeight()); + assertEquals(512, contentPageImages.get(2).getRawWidth()); + assertEquals(512, contentPageImages.get(2).getRawHeight()); + + // For the second image we force the server-side resize. + assertEquals(100, contentPageImages.get(1).getRawWidth()); + assertEquals(100, contentPageImages.get(1).getRawHeight()); } } diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml index 329a765ce00e..55e2a14d203c 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml @@ -822,6 +822,38 @@ require([ }).wrap("<span></span>"); }; + /** + * Removes the image size (width and height) from the image URL query string in order to prevent the server-side + * resize of the image, thus allowing the full size image to be included in the generated PDF. + */ + async function disableServerSideImageResize() { + const imageLoadPromises = [] + document.querySelectorAll('#xwikicontent img:not(.force-server-side-resize)').forEach(image => { + const imageURL = new URL(image.src); + const imageParams = imageURL.searchParams; + if (imageParams.has('width') || imageParams.has('height')) { + // Backup the original query string before we modify the image URL. + const oldImageQueryString = imageURL.search; + // The image size is specified in the URL which may trigger a server-side resize. We want the full image to be + // included in the PDF so let's remove these parameters. + imageParams.delete('width'); + imageParams.delete('height'); + const newImageQueryString = '?' + imageParams.toString(); + const newImageSrc = image.getAttribute('src').replace(oldImageQueryString, newImageQueryString); + // Create a promise for when the full size image is loaded. + imageLoadPromises.push(new Promise((resolve, reject) => { + image.addEventListener('load', resolve); + image.addEventListener('error', reject); + image.addEventListener('abort', resolve); + image.setAttribute('src', newImageSrc); + })); + } + }); + await Promise.allSettled(imageLoadPromises); + } + + pageReady.delayPageReady(disableServerSideImageResize(), 'Disable server-side image resize.'); + // Adjust the exported content before performing the print layout. pageReady.afterPageReady(() => { refactorAnchors(); diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml index 9cdf8b94f0cd..f403d803ecbe 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml @@ -110,4 +110,4 @@ XWiki.PDFExport.ConfigurationClass_maxContentSize.hint=단일 PDF 내보내기 XWiki.PDFExport.ConfigurationClass_replaceFOP=FOP 교체 XWiki.PDFExport.ConfigurationClass_replaceFOP.hint=Apache Formatting Objects Processor(FOP)를 기반으로 이전 PDF 내보내기를 대체합니다. - + diff --git a/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml b/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml index aa1d8a801278..626f9ba71a08 100644 --- a/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml +++ b/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml @@ -34,6 +34,8 @@ Font Awesome Icon Theme + + icontheme diff --git a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java index f35d9fd11d40..a530f5e9ba7c 100644 --- a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java +++ b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java @@ -21,18 +21,19 @@ import java.net.URL; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; import org.xwiki.model.reference.WikiReference; -import org.xwiki.test.mockito.MockitoComponentMockingRule; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; import org.xwiki.url.ExtendedURL; import org.xwiki.wiki.descriptor.WikiDescriptor; import org.xwiki.wiki.descriptor.WikiDescriptorManager; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; /** @@ -41,78 +42,81 @@ * @version $Id$ * @since 6.3M1 */ -public class PathWikiReferenceExtractorTest +@ComponentTest +class PathWikiReferenceExtractorTest { - @Rule - public MockitoComponentMockingRule mocker = - new MockitoComponentMockingRule<>(PathWikiReferenceExtractor.class); + @InjectMockComponents + private PathWikiReferenceExtractor extractor; + @MockComponent private WikiDescriptorManager wikiDescriptorManager; - @Before - public void setUp() throws Exception + @MockComponent + private Execution execution; + + @MockComponent + private StandardURLConfiguration urlConfiguration; + + @BeforeEach + void setUp() throws Exception { - this.wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getMainWikiId()).thenReturn("xwiki"); + when(this.wikiDescriptorManager.getMainWikiId()).thenReturn("xwiki"); } @Test - public void extractWhenWikiDescriptor() throws Exception + void extractWhenWikiDescriptor() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("wikiid", "someWiki")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("wikiid", "someWiki")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "wikiid"); } @Test - public void extractWhenNoWikiDescriptor() throws Exception + void extractWhenNoWikiDescriptor() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenWikiDescriptorButEmptyServerName() throws Exception + void extractWhenWikiDescriptorButEmptyServerName() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("", "someWiki")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("", "someWiki")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenNoDescriptorMatchingAliasButDescriptorMatchingId() throws Exception + void extractWhenNoDescriptorMatchingAliasButDescriptorMatchingId() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(null); - when(wikiDescriptorManager.getById("someWiki")).thenReturn(new WikiDescriptor("dummy", "dummy")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(null); + when(this.wikiDescriptorManager.getById("someWiki")).thenReturn(new WikiDescriptor("dummy", "dummy")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); } @Test - public void extractWhenNoWikiDescriptorButWithDomainBasedURL() throws Exception + void extractWhenNoWikiDescriptorButWithDomainBasedURL() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); testAndAssert("http://wiki.server.com/xwiki/bin/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenNoWikiDescriptorAndDisplayErrorWhenWikiNotFound() throws Exception + void extractWhenNoWikiDescriptorAndDisplayErrorWhenWikiNotFound() throws Exception { setUpConfiguration(WikiNotFoundBehavior.DISPLAY_ERROR); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); } @Test - public void extractWhenNoExecutionContext() throws Exception + void extractWhenNoExecutionContext() throws Exception { testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); @@ -125,19 +129,16 @@ private void testAndAssert(String urlToTest, String expectedWikiId) throws Excep ExtendedURL url = new ExtendedURL(new URL(urlToTest), "xwiki"); // Remove the resource type (i.e. the first segment) since this is what is expected by the extractor url.getSegments().remove(0); - WikiReference wikiReference = this.mocker.getComponentUnderTest().extract(url); + WikiReference wikiReference = this.extractor.extract(url); assertEquals(new WikiReference(expectedWikiId), wikiReference); } - private void setUpConfiguration(WikiNotFoundBehavior wikiNotFoundBehavior) throws Exception + private void setUpConfiguration(WikiNotFoundBehavior wikiNotFoundBehavior) { // Simulate a configured Execution Context - Execution execution = mocker.getInstance(Execution.class); ExecutionContext executionContext = new ExecutionContext(); executionContext.setProperty("xwikicontext", true); - when(execution.getContext()).thenReturn(executionContext); - - StandardURLConfiguration urlConfiguration = mocker.getInstance(StandardURLConfiguration.class); - when(urlConfiguration.getWikiNotFoundBehavior()).thenReturn(wikiNotFoundBehavior); + when(this.execution.getContext()).thenReturn(executionContext); + when(this.urlConfiguration.getWikiNotFoundBehavior()).thenReturn(wikiNotFoundBehavior); } } diff --git a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java index 45bc91da00b1..1f387fdc9e1e 100644 --- a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java +++ b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java @@ -19,8 +19,9 @@ */ package org.xwiki.url.internal.standard; -import org.junit.Rule; -import org.junit.Test; +import javax.inject.Named; + +import org.junit.jupiter.api.Test; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.component.manager.ComponentManager; import org.xwiki.component.util.DefaultParameterizedType; @@ -28,11 +29,13 @@ import org.xwiki.resource.ResourceReferenceSerializer; import org.xwiki.resource.ResourceType; import org.xwiki.resource.UnsupportedResourceReferenceException; -import org.xwiki.test.mockito.MockitoComponentMockingRule; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; import org.xwiki.url.ExtendedURL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; /** @@ -41,11 +44,15 @@ * @version $Id$ * @since 6.1M2 */ -public class StandardExtendedURLResourceReferenceSerializerTest +@ComponentTest +class StandardExtendedURLResourceReferenceSerializerTest { - @Rule - public MockitoComponentMockingRule mocker = - new MockitoComponentMockingRule<>(StandardExtendedURLResourceReferenceSerializer.class); + @InjectMockComponents + private StandardExtendedURLResourceReferenceSerializer serializer; + + @MockComponent + @Named("context") + private ComponentManager componentManager; public class TestResourceReference extends AbstractResourceReference { @@ -56,41 +63,37 @@ public TestResourceReference() } @Test - public void serialize() throws Exception + void serialize() throws Exception { TestResourceReference resource = new TestResourceReference(); ResourceReferenceSerializer serializer = mock(ResourceReferenceSerializer.class); - ComponentManager componentManager = this.mocker.getInstance(ComponentManager.class, "context"); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class), "standard")).thenReturn(serializer); - this.mocker.getComponentUnderTest().serialize(resource); + this.serializer.serialize(resource); // Verify the serializer is called and with the proper parameters verify(serializer).serialize(same(resource)); } @Test - public void serializeWhenNoMatchingSerializer() throws Exception + void serializeWhenNoMatchingSerializer() throws Exception { TestResourceReference resource = new TestResourceReference(); - ComponentManager componentManager = this.mocker.getInstance(ComponentManager.class, "context"); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class), "standard")).thenThrow( new ComponentLookupException("error")); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class))).thenThrow( new ComponentLookupException("error")); - try { - this.mocker.getComponentUnderTest().serialize(resource); - fail("Should have thrown an exception here"); - } catch (UnsupportedResourceReferenceException expected) { - assertEquals("Failed to find serializer for Resource Reference [type = [test], parameters = []] and " - + "URL format [standard]", expected.getMessage()); - } + Throwable exception = assertThrows(UnsupportedResourceReferenceException.class, () -> { + this.serializer.serialize(resource); + }); + assertEquals("Failed to find serializer for Resource Reference [type = [test], parameters = []] and " + + "URL format [standard]", exception.getMessage()); } } \ No newline at end of file