Skip to content

PowerPoint2007 Writer : Keep the borders a cell asked for - #906

Open
dkulyk wants to merge 1 commit into
PHPOffice:masterfrom
sapientpro:fix/table-cell-borders
Open

PowerPoint2007 Writer : Keep the borders a cell asked for#906
dkulyk wants to merge 1 commit into
PHPOffice:masterfrom
sapientpro:fix/table-cell-borders

Conversation

@dkulyk

@dkulyk dkulyk commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes #808

AbstractSlide::writeShapeTable() hands the edge shared by two neighbouring cells to one of them, which is sound. But it inspects the opposite side of the neighbour from the one it then copies:

// src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php:530
if ($hasNextCellRight) {
    $nextCellRight = $shape->getRow($row)->getCell($cell + 1);
    if ($nextCellRight->getBorders()->getRight()->getHashCode() != $defaultBorder->getHashCode()) {
        $borderRight = $nextCellRight->getBorders()->getLeft();   // guard tested RIGHT, copies LEFT
    }
}
if ($hasNextRowBelow) {
    $nextCellBelow = $shape->getRow($row + 1)->getCell($cell);
    if ($nextCellBelow->getBorders()->getBottom()->getHashCode() != $defaultBorder->getHashCode()) {
        $borderBottom = $nextCellBelow->getBorders()->getTop();   // guard tested BOTTOM, copies TOP
    }
}

So a cell loses the borders it owns as soon as it has a neighbour on that side, and the rule that replaces them is whatever the neighbour has on the facing side — usually the default. Left and top are never overridden, which is exactly the "left works, bottom does not" shape of the report.

Measured

A two-column, three-row table where every cell sets its own right and bottom rule (LINE_THICKTHIN / LINE_DOUBLE):

cell a:lnR before a:lnB before after
r0c0 sng sng thickThin / dbl
r0c1 thickThin sng thickThin / dbl
r1c0 sng sng thickThin / dbl
r1c1 thickThin sng thickThin / dbl
r2c0 sng dbl thickThin / dbl
r2c1 thickThin dbl thickThin / dbl

Eight of the twelve rules were dropped. Only the last column kept its right border and only the last row its bottom one — the two positions with no neighbour to be overridden by.

The fix

Inspect the side that is copied, the one facing this cell. The neighbour still wins the shared edge, but only when the neighbour is the one that asked for it — verified separately: a right neighbour that sets only its left border, and a cell below that sets only its top, both land on the top left cell as before.

Worth noting for anyone who worked around this: the old code required setting both sides of the neighbour — its right (to trip the guard) and its left (to supply the value). Setting just the facing side now works, and setting the border on the cell that owns it works too.

Checklist:

  • My CI is 🟢
  • I have covered by unit tests my new code (check build/coverage for coverage report)
    The existing testTableWithBorder passes unchanged, which is the problem — its XPath .../a:tr/a:tc/a:tcPr matches any cell in any row, so default borders satisfied it. PptSlidesTest::testTableWithBorderOnEveryCell and testTableWithBorderOwnedByTheNeighbour anchor on a:tr[1]/a:tc[1], the one cell that has both a neighbour to its right and a row below. Both fail on the current code and pass on the fix, and both are schema-validated.
  • I have updated the documentation to describe the changes
    docs/usage/shapes/table.md said nothing about borders at all. New Define the borders section, including the sharing rule — which is what tells a caller which cell to set.
  • I have updated the changelog

@coveralls

coveralls commented Aug 20, 2026

Copy link
Copy Markdown

Coverage Status

coverage: 92.159%. remained the same — sapientpro:fix/table-cell-borders into PHPOffice:master

@dkulyk
dkulyk force-pushed the fix/table-cell-borders branch from 2690cbf to f4ed149 Compare August 22, 2026 10:27
The block under "Fix PowerPoint implementation" hands a shared edge to one of
the two cells that touch it, which is sound, but it inspects the opposite side
of the neighbour from the one it then copies: the right border is replaced by
the neighbour's left whenever the neighbour's *right* is non-default, and the
bottom by the cell below's top whenever that cell's *bottom* is non-default.

So a cell lost the borders it owns as soon as it had a neighbour on that side.
Measured on a two-column, three-row table where every cell sets its own right
and bottom rule: only the last column kept its right border and only the last
row kept its bottom one, the other eight edges falling back to the default.

Inspect the side that is copied -- the one facing this cell. The neighbour
still wins the shared edge, but only when the neighbour is the one that asked
for it.
@dkulyk
dkulyk force-pushed the fix/table-cell-borders branch from f4ed149 to 018a371 Compare August 23, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

how to border left and border bottom in powerpoint2007?

2 participants